diff --git a/.icons/personalize.svg b/.icons/personalize.svg
index 778808d..31a9ad8 100644
--- a/.icons/personalize.svg
+++ b/.icons/personalize.svg
@@ -13,4 +13,4 @@
-
\ No newline at end of file
+
diff --git a/.images/aws-regions.png b/.images/aws-regions.png
new file mode 100644
index 0000000..4a79efe
Binary files /dev/null and b/.images/aws-regions.png differ
diff --git a/.images/gcp-regions.png b/.images/gcp-regions.png
new file mode 100644
index 0000000..1e0c362
Binary files /dev/null and b/.images/gcp-regions.png differ
diff --git a/.images/jetbrains-gateway.png b/.images/jetbrains-gateway.png
new file mode 100644
index 0000000..75807f6
Binary files /dev/null and b/.images/jetbrains-gateway.png differ
diff --git a/.images/jupyterlab.webp b/.images/jupyterlab.webp
new file mode 100644
index 0000000..d87f7c0
Binary files /dev/null and b/.images/jupyterlab.webp differ
diff --git a/.images/vscode-server.gif b/.images/vscode-server.gif
new file mode 100644
index 0000000..dcc563c
Binary files /dev/null and b/.images/vscode-server.gif differ
diff --git a/.sample/README.md b/.sample/README.md
new file mode 100644
index 0000000..ebc3e49
--- /dev/null
+++ b/.sample/README.md
@@ -0,0 +1,65 @@
+---
+display_name: MODULE_NAME
+description: Describe what this module does
+icon: ../.icons/.svg
+maintainer_github: GITHUB_USERNAME
+verified: false
+tags: [helper]
+---
+
+# MODULE_NAME
+
+
+
+
+
+```hcl
+module "MODULE_NAME" {
+ source = "https://registry.coder.com/modules/MODULE_NAME"
+}
+```
+
+## Examples
+
+### Example 1
+
+Install the Dracula theme from [OpenVSX](https://open-vsx.org/):
+
+```hcl
+module "MODULE_NAME" {
+ source = "https://registry.coder.com/modules/MODULE_NAME"
+ agent_id = coder_agent.example.id
+ extensions = [
+ "dracula-theme.theme-dracula"
+ ]
+}
+```
+
+Enter the `.` into the extensions array and code-server will automatically install on start.
+
+### Example 2
+
+Configure VS Code's [settings.json](https://code.visualstudio.com/docs/getstarted/settings#_settingsjson) file:
+
+```hcl
+module "MODULE_NAME" {
+ source = "https://registry.coder.com/modules/MODULE_NAME"
+ agent_id = coder_agent.example.id
+ extensions = [ "dracula-theme.theme-dracula" ]
+ settings = {
+ "workbench.colorTheme" = "Dracula"
+ }
+}
+```
+
+### Example 3
+
+Run code-server in the background, don't fetch it from GitHub:
+
+```hcl
+module "MODULE_NAME" {
+ source = "https://registry.coder.com/modules/MODULE_NAME"
+ agent_id = coder_agent.example.id
+ offline = true
+}
+```
diff --git a/.sample/main.tf b/.sample/main.tf
new file mode 100644
index 0000000..5dcaf01
--- /dev/null
+++ b/.sample/main.tf
@@ -0,0 +1,101 @@
+terraform {
+ required_version = ">= 1.0"
+
+ required_providers {
+ coder = {
+ source = "coder/coder"
+ version = ">= 0.12"
+ }
+ }
+}
+
+locals {
+ # A built-in icon like "/icon/code.svg" or a full URL of icon
+ icon_url = "https://raw.githubusercontent.com/coder/coder/main/site/static/icon/code.svg"
+ # a map of all possible values
+ options = {
+ "Option 1" = {
+ "name" = "Option 1",
+ "value" = "1"
+ "icon" = "/emojis/1.png"
+ }
+ "Option 2" = {
+ "name" = "Option 2",
+ "value" = "2"
+ "icon" = "/emojis/2.png"
+ }
+ }
+}
+
+# Add required variables for your modules and remove any unneeded variables
+variable "agent_id" {
+ type = string
+ description = "The ID of a Coder agent."
+}
+
+variable "log_path" {
+ type = string
+ description = "The path to log MODULE_NAME to."
+ default = "/tmp/MODULE_NAME.log"
+}
+
+variable "port" {
+ type = number
+ description = "The port to run MODULE_NAME on."
+ default = 19999
+}
+
+variable "mutable" {
+ type = bool
+ description = "Whether the parameter is mutable."
+ default = true
+}
+# Add other variables here
+
+
+resource "coder_script" "MODULE_NAME" {
+ agent_id = var.agent_id
+ display_name = "MODULE_NAME"
+ icon = local.icon_url
+ script = templatefile("${path.module}/run.sh", {
+ LOG_PATH : var.log_path,
+ })
+ run_on_start = true
+ run_on_stopt = false
+}
+
+resource "coder_app" "MODULE_NAME" {
+ agent_id = var.agent_id
+ slug = "MODULE_NAME"
+ display_name = "MODULE_NAME"
+ url = "http://localhost:${var.port}"
+ icon = loocal.icon_url
+ subdomain = false
+ share = "owner"
+
+ # Remove if the app does not have a healthcheck endpoint
+ healthcheck {
+ url = "http://localhost:${var.port}/healthz"
+ interval = 5
+ threshold = 6
+ }
+}
+
+data "coder_parameter" "MODULE_NAME" {
+ type = "list(string)"
+ name = "MODULE_NAME"
+ display_name = "MODULE_NAME"
+ icon = local.icon_url
+ mutable = var.mutable
+ default = local.options["Option 1"]["value"]
+
+ dynamic "option" {
+ for_each = local.options
+ content {
+ icon = option.value.icon
+ name = option.value.name
+ value = option.value.value
+ }
+ }
+}
+
diff --git a/.sample/run.sh b/.sample/run.sh
new file mode 100755
index 0000000..88af7ad
--- /dev/null
+++ b/.sample/run.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env sh
+
+echo "Instalalting ${MODULE_NAME}..."
+# Add code here
+# Use varibles from the templatefile function in main.tf
+# e.g. LOG_PATH, PORT, etc.
+
+echo "Installation comlete!"
+
+echo "Starting ${MODULE_NAME}..."
+# Start the app in here
+# 1. Use & to run it in background
+# 2. redirct stdout and stderr to log files
+
+./app >${LOG_PATH} 2>&1 &
+
+echo "Sample app started!"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..eb8d484
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,42 @@
+# Contributing
+
+To create a new module, clone this repository and run:
+
+```shell
+./new.sh MOUDLE_NAME
+```
+
+Test a module by running an instance of Coder on your local machine:
+
+```shell
+coder server --in-memory
+```
+
+This will create a new module in the modules directory with the given name and scaffolding.
+Edit the files, adding your module's implementation, documentation and screenshots.
+
+## Testing a Module
+
+Create a template and edit it to include your development module:
+
+> [!NOTE]
+> The Docker starter template is recommended for quick-iteration!
+
+```hcl
+module "MOUDLE_NAME" {
+ source = "/home/user/coder/modules/MOUDLE_NAME"
+}
+```
+
+You can also test your module by specifying the source as a git repository:
+
+```hcl
+module "MOUDLE_NAME" {
+ source = "git::https://github.com//.git//?ref="
+}
+```
+
+Build a workspace and your module will be consumed! 🥳
+
+Open a pull-request with your module, a member of the Coder team will
+manually test it, and after-merge it will appear on the Registry.
diff --git a/README.md b/README.md
index 308a45e..b01b24d 100644
--- a/README.md
+++ b/README.md
@@ -32,30 +32,4 @@ Check out the [Coder Registry](https://registry.coder.com) for instructions to i
## Contributing a Module
-To quickly start contributing with a new module, clone this repository and run:
-
-```sh
-./new.sh
-```
-
-Test a module by running an instance of Coder on your local machine:
-
-```bash
-coder server --in-memory
-```
-
-Create a template and edit it to include your development module:
-
-> *Info*
-> The Docker starter template is recommended for quick-iteration!
-
-```tf
-module "testing" {
- source = "/home/user/coder/modules/my-new-module"
-}
-```
-
-Build a workspace and your module will be consumed! 🥳
-
-Open a pull-request with your module, a member of the Coder team will
-manually test it, and after-merge it will appear on the Registry.
+See [CONTRIBUTING.md](./CONTRIBUTING.md) for instructions on how to construct and publish a module to the [Coder Registry](https://registry.coder.com).
diff --git a/aws-region/README.md b/aws-region/README.md
index ecd27ac..1051cc6 100644
--- a/aws-region/README.md
+++ b/aws-region/README.md
@@ -4,7 +4,7 @@ description: A parameter with human region names and icons
icon: ../.icons/aws.svg
maintainer_github: coder
verified: true
-tags: [helper, parameter]
+tags: [helper, parameter, regions, aws]
---
# AWS Region
@@ -12,6 +12,8 @@ tags: [helper, parameter]
A parameter with all AWS regions. This allows developers to select
the region closest to them.
+
+
## Examples
### Default Region
diff --git a/azure-region/README.md b/azure-region/README.md
index e630933..cb14303 100644
--- a/azure-region/README.md
+++ b/azure-region/README.md
@@ -4,7 +4,7 @@ description: A parameter with human region names and icons
icon: ../.icons/azure.svg
maintainer_github: coder
verified: true
-tags: [helper, parameter, azure]
+tags: [helper, parameter, azure, regions]
---
# Azure Region
@@ -59,4 +59,4 @@ module "azure-region" {
resource "azurerm_resource_group" "example" {
location = module.azure_region.value
}
-```
\ No newline at end of file
+```
diff --git a/code-server/README.md b/code-server/README.md
index 6f068ed..9f360e1 100644
--- a/code-server/README.md
+++ b/code-server/README.md
@@ -4,7 +4,7 @@ description: VS Code in the browser
icon: ../.icons/code.svg
maintainer_github: coder
verified: true
-tags: [helper, ide]
+tags: [helper, ide, web]
---
# code-server
@@ -63,4 +63,4 @@ module "settings" {
agent_id = coder_agent.example.id
offline = true
}
-```
\ No newline at end of file
+```
diff --git a/gcp-region/README.md b/gcp-region/README.md
index 9407845..553a8fd 100644
--- a/gcp-region/README.md
+++ b/gcp-region/README.md
@@ -1,32 +1,47 @@
---
-display_name: GCP Regions
+display_name: GCP Region
description: Add Google Cloud Platform regions to your Coder template.
icon: ../.icons/gcp.svg
maintainer_github: coder
verified: true
-tags: [gcp, regions, zones, helper]
+tags: [gcp, regions, parameter, helper]
---
# Google Cloud Platform Regions
This module adds Google Cloud Platform regions to your Coder template.
+
+
## Examples
1. Add only GPU zones in the US West 1 region:
```hcl
- module "regions" {
- source = "https://registry.coder.com/modules/gcp-regions"
- default = ["us-west1"]
- gpu_only = true
+ module "gcp_region" {
+ source = "https://registry.coder.com/modules/gcp-region"
+ default = ["us-west1-a"]
+ regions = ["us-west1"]
+ gpu_only = false
}
```
2. Add all zones in the Europe West region:
```hcl
- module "regions" {
- source = "https://registry.coder.com/modules/gcp-regions"
- default = ["europe-west"]
+ module "gcp_region" {
+ source = "https://registry.coder.com/modules/gcp-region"
+ regions = ["europe-west"]
+ single_zone_per_region = false
+ }
+ ```
+
+3. Add a single zone from each region in US and Europe that laos has GPUs
+
+ ```hcl
+ module "gcp_region" {
+ source = "https://registry.coder.com/modules/gcp-region"
+ regions = ["us", "europe"]
+ gpu_only = true
+ single_zone_per_region = true
}
```
diff --git a/gcp-region/main.tf b/gcp-region/main.tf
index 1114466..4d675c8 100644
--- a/gcp-region/main.tf
+++ b/gcp-region/main.tf
@@ -22,6 +22,12 @@ variable "description" {
}
variable "default" {
+ default = null
+ description = "Default zone"
+ type = string
+}
+
+variable "regions" {
description = "List of GCP regions to include."
type = list(string)
default = ["us-central1"]
@@ -51,6 +57,12 @@ variable "custom_icons" {
type = map(string)
}
+variable "single_zone_per_region" {
+ default = true
+ description = "Whether to only include a single zone per region."
+ type = bool
+}
+
locals {
zones = {
# US Central
@@ -343,17 +355,17 @@ locals {
"europe-west2-a" = {
gpu = true
name = "London, England (a)"
- icon = "/emojis/1f173-1f1ff.png"
+ icon = "/emojis/1f1ec-1f1e7.png"
}
"europe-west2-b" = {
gpu = true
name = "London, England (b)"
- icon = "/emojis/1f173-1f1ff.png"
+ icon = "/emojis/1f1ec-1f1e7.png"
}
"europe-west2-c" = {
gpu = false
name = "London, England (c)"
- icon = "/emojis/1f173-1f1ff.png"
+ icon = "/emojis/1f1ec-1f1e7.png"
}
"europe-west3-b" = {
@@ -702,14 +714,16 @@ data "coder_parameter" "region" {
description = var.description
icon = "/icon/gcp.png"
mutable = var.mutable
+ default = var.default != null && var.default != "" ? var.default : null
dynamic "option" {
for_each = {
for k, v in local.zones : k => v
- if anytrue([for d in var.default : startswith(k, d)]) && (!var.gpu_only || v.gpu)
+ if anytrue([for d in var.regions : startswith(k, d)]) && (!var.gpu_only || v.gpu) && (!var.single_zone_per_region || endswith(k, "-a"))
}
content {
- icon = try(var.custom_icons[option.key], option.value.icon)
- name = try(var.custom_names[option.key], option.value.name)
+ icon = try(var.custom_icons[option.key], option.value.icon)
+ # if single_zone_per_region is true, remove the zone letter from the name
+ name = try(var.custom_names[option.key], var.single_zone_per_region ? substr(option.value.name, 0, length(option.value.name) - 4) : option.value.name)
description = option.key
value = option.key
}
@@ -717,5 +731,11 @@ data "coder_parameter" "region" {
}
output "value" {
- value = data.coder_parameter.region.value
+ description = "GCP zone identifier."
+ value = data.coder_parameter.region.value
+}
+
+output "region" {
+ description = "GCP region identifier."
+ value = substr(data.coder_parameter.region.value, 0, length(data.coder_parameter.region.value) - 2)
}
diff --git a/jetbrains-gateway/README.md b/jetbrains-gateway/README.md
index 3b67d22..7abe4d2 100644
--- a/jetbrains-gateway/README.md
+++ b/jetbrains-gateway/README.md
@@ -4,29 +4,32 @@ description: Add a one-click button to launch JetBrains Gateway IDEs in the dash
icon: ../.icons/gateway.svg
maintainer_github: coder
verified: true
-tags: [ide, jetbrains, gateway, goland, webstorm, intellij, pycharm, phpstorm, clion, rubymine, datagrip, rider]
+tags: [ide, jetbrains, helper, parameter]
---
# JetBrains Gateway
-This module adds a JetBrains Gateway IDEs to your Coder template.
+This module adds a JetBrains Gateway Button to open any workspace with a single click.
-## How to use this module
+
-To use this module, add the following snippet to your template manifest:
+## Examples
+
+### Add GoLand and WebStorm with the default set to GoLand
```hcl
module "jetbrains_gateway" {
source = "https://registry.coder.com/modules/jetbrains-gateway"
- agent_id = coder_agent.main.id
- agent_name = "main"
- project_directory = "/home/coder/project"
- gateway_ide_product_code = ["GO","WS"] # A list of JetBrains product codes use ["ALL"] for all products
+ agent_id = coder_agent.example.id
+ agent_name = "example"
+ project_directory = "/home/coder/example"
+ jetbrains_ides = ["GO", "WS"]
+ default = "GO"
}
```
## Supported IDEs
-The following JetBrains IDEs are supported:
+This module and JetBrains Gateway support the following JetBrains IDEs:
- GoLand (`GO`)
- WebStorm (`WS`)
diff --git a/jetbrains-gateway/main.tf b/jetbrains-gateway/main.tf
index 993ea41..9e01cf0 100644
--- a/jetbrains-gateway/main.tf
+++ b/jetbrains-gateway/main.tf
@@ -24,23 +24,26 @@ variable "project_directory" {
description = "The directory to open in the IDE. e.g. /home/coder/project"
}
-variable "gateway_ide_product_code" {
+variable "default" {
+ type = string
+ description = "Default IDE"
+}
+
+variable "jetbrains_ides" {
type = list(string)
- description = "The list of IDE product codes, e.g. ['GO', 'WS'] or ['ALL']"
- default = ["ALL"]
+ description = "The list of IDE product codes."
validation {
condition = (
- length(var.gateway_ide_product_code) == 1 && var.gateway_ide_product_code[0] == "ALL" ||
alltrue([
- for code in var.gateway_ide_product_code : contains(["IU", "IC", "PS", "WS", "PY", "PC", "CL", "GO", "DB", "RD", "RM"], code)
+ for code in var.jetbrains_ides : contains(["IU", "IC", "PS", "WS", "PY", "PC", "CL", "GO", "DB", "RD", "RM"], code)
])
)
- error_message = "The gateway_ide_product_code must be ['ALL'] or a list of valid product codes. https://plugins.jetbrains.com/docs/marketplace/product-codes.html"
+ error_message = "The jetbrains_ides must be a list of valid product codes. https://plugins.jetbrains.com/docs/marketplace/product-codes.html"
}
}
locals {
- gateway_ides = {
+ jetbrains_ides = {
"GO" = {
icon = "/icon/goland.svg",
name = "GoLand",
@@ -105,10 +108,10 @@ data "coder_parameter" "jetbrains_ide" {
display_name = "JetBrains IDE"
icon = "/icon/gateway.svg"
mutable = true
- default = local.gateway_ides["GO"].value
+ default = var.default != null && var.default != "" ? local.jetbrains_ides[var.default].value : null
dynamic "option" {
- for_each = contains(var.gateway_ide_product_code, "ALL") ? local.gateway_ides : { for key, value in local.gateway_ides : key => value if contains(var.gateway_ide_product_code, key) }
+ for_each = { for key, value in local.jetbrains_ides : key => value if contains(var.jetbrains_ides, key) }
content {
icon = option.value.icon
name = option.value.name
@@ -127,3 +130,7 @@ resource "coder_app" "gateway" {
icon = data.coder_parameter.jetbrains_ide.option[index(data.coder_parameter.jetbrains_ide.option.*.value, data.coder_parameter.jetbrains_ide.value)].icon
external = true
}
+
+output "jetbrains_ides" {
+ value = data.coder_parameter.jetbrains_ide.value
+}
diff --git a/jupyterhub/README.md b/jupyterhub/README.md
deleted file mode 100644
index ab123ed..0000000
--- a/jupyterhub/README.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-display_name: JupyterHub
-description: A multi-user version of the notebook designed for companies, classrooms and research labs
-icon: ../.icons/jupyter.svg
-maintainer_github: coder
-verified: true
-tags: [helper, ide]
----
-
-# JupyterHub
-
-Automatically install [JupyterHub](https://jupyter.org/hub) in a workspace, and create an app to access it via the dashboard.
-
-## Examples
-
-TODO
\ No newline at end of file
diff --git a/jupyterlab/README.md b/jupyterlab/README.md
new file mode 100644
index 0000000..d551f96
--- /dev/null
+++ b/jupyterlab/README.md
@@ -0,0 +1,21 @@
+---
+display_name: JupyterLab
+description: A module that adds JupyterLab in your Coder template.
+icon: ../.icons/jupyter.svg
+maintainer_github: coder
+verified: true
+tags: [jupyter, helper, ide, web]
+---
+
+# JupyterLab
+
+A module that adds JupyterLab in your Coder template.
+
+
+
+```hcl
+module "jupyterlab" {
+ source = "https://registry.coder.com/modules/jupyterlab"
+ agent_id = coder_agent.example.id
+}
+```
diff --git a/jupyterlab/main.tf b/jupyterlab/main.tf
new file mode 100644
index 0000000..e95c0a2
--- /dev/null
+++ b/jupyterlab/main.tf
@@ -0,0 +1,54 @@
+terraform {
+ required_version = ">= 1.0"
+
+ required_providers {
+ coder = {
+ source = "coder/coder"
+ version = ">= 0.12"
+ }
+ }
+}
+
+locals {
+ icon_url = "/icon/jupyter.svg"
+}
+
+# Add required variables for your modules and remove any unneeded variables
+variable "agent_id" {
+ type = string
+ description = "The ID of a Coder agent."
+}
+
+variable "log_path" {
+ type = string
+ description = "The path to log jupyterlab to."
+ default = "/tmp/jupyterlab.log"
+}
+
+variable "port" {
+ type = number
+ description = "The port to run jupyterlab on."
+ default = 19999
+}
+
+resource "coder_script" "jupyterlab" {
+ agent_id = var.agent_id
+ display_name = "jupyterlab"
+ icon = local.icon_url
+ script = templatefile("${path.module}/run.sh", {
+ LOG_PATH : var.log_path,
+ PORT : var.port
+ })
+ run_on_start = true
+ run_on_stopt = false
+}
+
+resource "coder_app" "jupyterlab" {
+ agent_id = var.agent_id
+ slug = "jupyterlab"
+ display_name = "JupyterLab"
+ url = "http://localhost:${var.port}"
+ icon = local.icon_url
+ subdomain = true
+ share = "owner"
+}
diff --git a/jupyterlab/run.sh b/jupyterlab/run.sh
new file mode 100755
index 0000000..a3a484a
--- /dev/null
+++ b/jupyterlab/run.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env sh
+
+echo "Instalalting ${MODULE_NAME}..."
+
+# check if jupyterlab is installed
+if ! command -v jupyterlab &> /dev/null then
+ # install jupyterlab
+ # check if python3 pip is installed
+ if ! command -v pip3 &> /dev/null then
+ echo "pip3 is not installed"
+ echo "Please install pip3 and try again"
+ exit 1
+ fi
+ pip3 install jupyterlab
+ echo "jupyterlab installed!"
+fi
+
+echo "Starting ${MODULE_NAME}..."
+
+$HOME/.local/bin/jupyter lab --no-browser --LabApp.token='' --LabApp.password='' >${LOG_PATH} 2>&1 &
+
+echo "Started ${MODULE_NAME}!"
diff --git a/kasmvnc/README.md b/kasmvnc/README.md
index 1803268..0bfcaf9 100644
--- a/kasmvnc/README.md
+++ b/kasmvnc/README.md
@@ -4,7 +4,7 @@ description: A modern open source VNC server
icon: ../.icons/kasmvnc.svg
maintainer_github: coder
verified: true
-tags: [helper, ide]
+tags: [helper, VNC, web]
---
# KasmVNC
@@ -13,4 +13,27 @@ Automatically install [KasmVNC](https://kasmweb.com/kasmvnc) in a workspace, and
## Examples
-TODO
\ No newline at end of file
+1. Add latest version of KasmVNC with [`lxde`](https://www.lxde.org/) desktop environment:
+
+ ```hcl
+ module "kasmvnc" {
+ source = "https://registry.coder.com/modules/kasmvnc"
+ agent_id = coder_agent.example.id
+ }
+
+ ```
+
+2. Add specific version of KasmVNC with [`mate`](https://mate-desktop.org/) desktop environment and custom port:
+
+ ```hcl
+ module "kasmvnc" {
+ source = "https://registry.coder.com/modules/kasmvnc"
+ agent_id = coder_agent.example.id
+ version = "1.0.0"
+ desktop_environment = "mate"
+ port = 6080
+ }
+
+ ```
+
+![Screenshot of KasmVNC]() //TODO
diff --git a/kasmvnc/main.tf b/kasmvnc/main.tf
new file mode 100644
index 0000000..6fd0ba4
--- /dev/null
+++ b/kasmvnc/main.tf
@@ -0,0 +1,55 @@
+terraform {
+ required_version = ">= 1.0"
+
+ required_providers {
+ coder = {
+ source = "coder/coder"
+ version = ">= 0.12"
+ }
+ }
+}
+
+variable "agent_id" {
+ type = string
+ description = "The ID of a Coder agent."
+}
+
+variable "port" {
+ type = number
+ description = "The port to run KasmVNC on."
+ default = 8443
+}
+
+variable "desktop_environment" {
+ type = string
+ description = "The desktop environment to for KasmVNC (xfce, lxde, mate, etc)."
+ default = "lxde"
+}
+
+variable "version" {
+ type = string
+ description = "Version of KasmVNC to install."
+ default = "1.2.0"
+}
+
+resource "coder_script" "kasm_vnc" {
+ agent_id = var.agent_id
+ display_name = "KasmVNC"
+ icon = "/icon/kasmvnc.svg"
+ script = templatefile("${path.module}/run.sh", {
+ PORT : var.port,
+ DESKTOP_ENVIRONMENT : var.desktop_environment,
+ VERSION : var.version
+ })
+ run_on_start = true
+}
+
+resource "coder_app" "kasm_vnc" {
+ agent_id = var.agent_id
+ slug = "kasm-vnc"
+ display_name = "kasmVNC"
+ url = "http://localhost:${var.port}"
+ icon = "/icon/kasmvnc.svg"
+ subdomain = false
+ share = "owner"
+}
diff --git a/kasmvnc/run.sh b/kasmvnc/run.sh
new file mode 100644
index 0000000..7a59580
--- /dev/null
+++ b/kasmvnc/run.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+
+# Check if desktop enivronment is installed
+if ! dpkg -s ${DESKTOP_ENVIRONMENT} &>/dev/null; then
+ sudo apt-get update
+ DEBIAN_FRONTEND=noninteractive sudo apt-get install -y ${DESKTOP_ENVIRONMENT}
+else
+ echo "${DESKTOP_ENVIRONMENT} is already installed."
+fi
+
+# Check if vncserver is installed
+if ! dpkg -s kasmvncserver &>/dev/null; then
+ cd /tmp
+ wget https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_focal_${VERSION}_amd64.deb
+ sudo apt install -y ./kasmvncserver_focal_${VERSION}_amd64.deb
+ printf "🥳 KasmVNC v${VERSION} has been successfully installed!\n\n"
+else
+ echo "KasmVNC is already installed."
+fi
+
+sudo addgroup $USER ssl-cert
+
+# Coder port-forwarding from dashboard only supports HTTP
+sudo bash -c 'cat > /etc/kasmvnc/kasmvnc.yaml <"
+ exit 1
+fi
+
+# Create module directory and exit if it alredy exists
+if [ -d "$MODULE_NAME" ]; then
+ echo "Module with name $MODULE_NAME already exists"
+ echo "Please choose a different name"
+ exit 1
+fi
+mkdir -p "${MODULE_NAME}"
+
+# Copy required files from the sample module
+cp -r .sample/* "${MODULE_NAME}"
+
+# Change to module directory
+cd "${MODULE_NAME}"
+
+# Detect OS
+if [[ "$OSTYPE" == "darwin"* ]]; then
+ # macOS
+ sed -i '' "s/MODULE_NAME/${MODULE_NAME}/g" main.tf
+ sed -i '' "s/MODULE_NAME/${MODULE_NAME}/g" README.md
+else
+ # Linux
+ sed -i "s/MODULE_NAME/${MODULE_NAME}/g" main.tf
+ sed -i "s/MODULE_NAME/${MODULE_NAME}/g" README.md
+fi
+
+# Make run.sh executable
+chmod +x run.sh
diff --git a/vscode-desktop/README.md b/vscode-desktop/README.md
index 4ec37a1..c188c45 100644
--- a/vscode-desktop/README.md
+++ b/vscode-desktop/README.md
@@ -4,6 +4,7 @@ description: Add a one-click button to launch VS Code Desktop
icon: ../.icons/code.svg
maintainer_github: coder
verified: true
+tags: [ide, vscode, helper]
---
# VS Code Desktop
diff --git a/vscode-server/README.md b/vscode-server/README.md
new file mode 100644
index 0000000..dfbec39
--- /dev/null
+++ b/vscode-server/README.md
@@ -0,0 +1,38 @@
+---
+display_name: vscode-server
+description: VS Code Web - Visual Studio Code in the browser
+icon: ../.icons/code.svg
+maintainer_github: coder
+verified: true
+tags: [helper, ide, vscode, web]
+---
+
+# VS Code Web
+
+Automatically install [Visual Studio Code Server](https://code.visualstudio.com/docs/remote/vscode-server) in a workspace using the [VS Code CLIs](https://code.visualstudio.com/docs/editor/command-line) and create an app to access it via the dashboard.
+
+
+
+## Examples
+
+1. Install VS Code Server with default settings:
+
+ ```hcl
+ module "vscode-web" {
+ source = "https://registry.coder.com/modules/vscode-server"
+ agent_id = coder_agent.example.id
+ accept_license = true
+ }
+ ```
+
+2. Install VS Code Server to a custom folder:
+
+ ```hcl
+ module "vscode-web" {
+ source = "https://registry.coder.com/modules/vscode-server"
+ agent_id = coder_agent.example.id
+ install_dir = "/home/coder/.vscode-server"
+ folder = "/home/coder"
+ accept_license = true
+ }
+ ```
diff --git a/vscode-server/main.tf b/vscode-server/main.tf
new file mode 100644
index 0000000..bd86703
--- /dev/null
+++ b/vscode-server/main.tf
@@ -0,0 +1,77 @@
+terraform {
+ required_version = ">= 1.0"
+
+ required_providers {
+ coder = {
+ source = "coder/coder"
+ version = ">= 0.12"
+ }
+ }
+}
+
+variable "agent_id" {
+ type = string
+ description = "The ID of a Coder agent."
+}
+
+variable "port" {
+ type = number
+ description = "The port to run VS Code Web on."
+ default = 13338
+}
+
+variable "folder" {
+ type = string
+ description = "The folder to open in vscode-server."
+ default = ""
+}
+
+variable "log_path" {
+ type = string
+ description = "The path to log."
+ default = "/tmp/vscode-server.log"
+}
+
+variable "install_dir" {
+ type = string
+ description = "The directory to install VS Code CLI"
+ default = "/tmp/vscode-cli"
+}
+
+variable "accept_license" {
+ type = bool
+ description = "Accept the VS Code license. https://code.visualstudio.com/license"
+ default = false
+ validation {
+ condition = var.accept_license == true
+ error_message = "You must accept the VS Code license agreement by setting accept_license=true."
+ }
+}
+
+resource "coder_script" "vscode-server" {
+ agent_id = var.agent_id
+ display_name = "VS Code Web"
+ icon = "/icon/code.svg"
+ script = templatefile("${path.module}/run.sh", {
+ PORT : var.port,
+ LOG_PATH : var.log_path,
+ INSTALL_DIR : var.install_dir,
+ })
+ run_on_start = true
+}
+
+resource "coder_app" "vscode-server" {
+ agent_id = var.agent_id
+ slug = "vscode-server"
+ display_name = "VS Code Web"
+ url = var.folder == "" ? "http://localhost:${var.port}" : "http://localhost:${var.port}?folder=${var.folder}"
+ icon = "/icon/code.svg"
+ subdomain = true
+ share = "owner"
+
+ healthcheck {
+ url = "http://localhost:${var.port}/healthz"
+ interval = 5
+ threshold = 6
+ }
+}
diff --git a/vscode-server/run.sh b/vscode-server/run.sh
new file mode 100644
index 0000000..ddec273
--- /dev/null
+++ b/vscode-server/run.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env sh
+
+BOLD='\033[0;1m'
+
+# Create install directory if it doesn't exist
+mkdir -p ${INSTALL_DIR}
+
+printf "$${BOLD}Installing vscode-cli!\n"
+
+# Download and extract code-cli tarball
+output=$(curl -Lk 'https://code.visualstudio.com/sha/download?build=stable&os=cli-alpine-x64' --output vscode_cli.tar.gz && tar -xf vscode_cli.tar.gz -C ${INSTALL_DIR} && rm vscode_cli.tar.gz)
+
+if [ $? -ne 0 ]; then
+ echo "Failed to install vscode-cli: $output"
+ exit 1
+fi
+printf "🥳 vscode-cli has been installed.\n\n"
+
+echo "👷 Running ${INSTALL_DIR}/bin/code serve-web --port ${PORT} --without-connection-token --accept-server-license-terms in the background..."
+echo "Check logs at ${LOG_PATH}!"
+${INSTALL_DIR}/code serve-web --port ${PORT} --without-connection-token --accept-server-license-terms >${LOG_PATH} 2>&1 &