|
# retoor <retoor@molodetz.nl>
|
|
|
|
from .._shared import endpoint, field
|
|
|
|
GROUP = {
|
|
"slug": "workspaces",
|
|
"title": "Dev Workspaces",
|
|
"intro": """
|
|
# Dev Workspaces
|
|
|
|
A workspace is a browser editor attached to one of your projects. It runs your project files, a
|
|
terminal, and preinstalled Python, Rust, Nim and Swift toolchains. `sudo` and `apt install` work
|
|
with no extra setup; ports below 1024 cannot bind, so use a high port and publish it through a
|
|
tunnel.
|
|
|
|
The editor opens with a **DevPlace Code** terminal already running the `dpc` coding agent and a
|
|
plain shell beside it, and it trusts every folder, so nothing opens in Restricted Mode. Its
|
|
appearance and boot behaviour are your own preferences, readable and writable through the two
|
|
`/workspace/editor` endpoints below and explained on
|
|
[the workspace editor page](/docs/workspace-editor.html). Editor preferences apply on the next
|
|
workspace start.
|
|
|
|
A **tunnel** publishes one port from inside your container on a public HTTPS hostname of the form
|
|
`<port>-<name>.tunnel.pravda.education`. **Tunnel URLs are public and unauthenticated** - anyone with
|
|
the link can reach whatever you are serving.
|
|
|
|
Workspaces are bounded: a count limit per user, a disk quota, an egress quota, and a tunnel limit.
|
|
An idle workspace is warned about, then stopped, then warned again, then removed. Every warning
|
|
arrives as a `workspace` notification and states exactly what happens next and when.
|
|
""",
|
|
"endpoints": [
|
|
endpoint(
|
|
id="workspace-get",
|
|
method="GET",
|
|
path="/projects/{slug}/workspace",
|
|
title="Read workspace",
|
|
summary=(
|
|
"State, quota usage, idle countdown, tunnels and open moderation flags "
|
|
"for your workspace on this project."
|
|
),
|
|
auth="user",
|
|
params=[
|
|
field("slug", "path", "string", True, "my-project", "Project slug or uid."),
|
|
],
|
|
sample_response={
|
|
"has_workspace": True,
|
|
"viewer_can_workspace": True,
|
|
"workspace_count": 1,
|
|
"max_workspaces": 2,
|
|
"editor_url": "/projects/my-project/containers/instances/INSTANCE_UID/code/",
|
|
"workspace": {
|
|
"uid": "INSTANCE_UID",
|
|
"status": "running",
|
|
"suspended": False,
|
|
"tunnel_name": "brave-otter",
|
|
"primary_url": "https://brave-otter.tunnel.pravda.education",
|
|
"disk_bytes": 5242880,
|
|
"disk_quota_mb": 2048,
|
|
"disk_percent": 1,
|
|
"egress_bytes": 10240,
|
|
"egress_quota_mb": 10240,
|
|
"egress_percent": 0,
|
|
"idle_stop_minutes": 60,
|
|
"retention_days": 14,
|
|
"max_tunnels": 5,
|
|
"tunnels": [],
|
|
"flags": [],
|
|
},
|
|
},
|
|
),
|
|
endpoint(
|
|
id="workspace-open",
|
|
method="POST",
|
|
path="/projects/{slug}/workspace",
|
|
title="Open or resume workspace",
|
|
summary=(
|
|
"Create the workspace if you have none for this project, otherwise resume "
|
|
"it. Idempotent. Refused when you are at your workspace limit, over disk "
|
|
"quota, or suspended."
|
|
),
|
|
auth="user",
|
|
params=[
|
|
field("slug", "path", "string", True, "my-project", "Project slug or uid."),
|
|
],
|
|
sample_response={"ok": True, "redirect": "/projects/my-project/workspace"},
|
|
),
|
|
endpoint(
|
|
id="workspace-stop",
|
|
method="POST",
|
|
path="/projects/{slug}/workspace/stop",
|
|
title="Stop workspace",
|
|
summary="Stop the container. Files and tunnels are kept.",
|
|
auth="user",
|
|
params=[
|
|
field("slug", "path", "string", True, "my-project", "Project slug or uid."),
|
|
],
|
|
sample_response={"ok": True, "redirect": "/projects/my-project/workspace"},
|
|
),
|
|
endpoint(
|
|
id="workspace-delete",
|
|
method="POST",
|
|
path="/projects/{slug}/workspace/delete",
|
|
title="Delete workspace",
|
|
summary="Remove the workspace and its tunnels. An administrator can restore it.",
|
|
auth="user",
|
|
params=[
|
|
field("slug", "path", "string", True, "my-project", "Project slug or uid."),
|
|
],
|
|
sample_response={"ok": True, "redirect": "/projects/my-project/workspace"},
|
|
),
|
|
endpoint(
|
|
id="workspace-editor-get",
|
|
method="GET",
|
|
path="/projects/{slug}/workspace/editor",
|
|
title="Read editor profile",
|
|
summary=(
|
|
"The resolved DevPlace editor profile for this workspace: theme, layout, "
|
|
"panel preset, font sizes, zoom, boot terminals, how the editor opens, the "
|
|
"container size, and where each value comes from."
|
|
),
|
|
auth="user",
|
|
params=[
|
|
field("slug", "path", "string", True, "my-project", "Project slug or uid."),
|
|
],
|
|
sample_response={
|
|
"editor": {
|
|
"trust_all": True,
|
|
"theme": "devplace-dark",
|
|
"font_size": 14,
|
|
"terminal_font_size": 13,
|
|
"zoom_level": 0,
|
|
"layout": "standard",
|
|
"panel_preset": "tall",
|
|
"boot_agent": "dpc",
|
|
"boot_shell": True,
|
|
"window_mode": "tab",
|
|
"window_width": 1600,
|
|
"window_height": 1000,
|
|
"cpu_millicores": 2000,
|
|
"cpu_cores": 2.0,
|
|
"memory_mb": 2048,
|
|
"disk_quota_mb": 2048,
|
|
"sources": {"theme": "user", "font_size": "site"},
|
|
},
|
|
"restart_required": False,
|
|
},
|
|
),
|
|
endpoint(
|
|
id="workspace-editor-set",
|
|
method="POST",
|
|
path="/projects/{slug}/workspace/editor",
|
|
title="Set editor preferences",
|
|
summary=(
|
|
"Change your own editor preferences. Only the fields you send are "
|
|
"changed; within those, an empty string or zero means inherit the site "
|
|
"default, and `reset` drops every preference. Applies on the next "
|
|
"workspace start, and the response says whether a restart is needed."
|
|
),
|
|
auth="user",
|
|
params=[
|
|
field("slug", "path", "string", True, "my-project", "Project slug or uid."),
|
|
field("theme", "body", "string", False, "devplace-dark",
|
|
"devplace-dark, devplace-light or system."),
|
|
field("layout", "body", "string", False, "standard",
|
|
"standard, terminal-focus or zen."),
|
|
field("panel_preset", "body", "string", False, "tall",
|
|
"short, normal, tall or maximized."),
|
|
field("font_size", "body", "integer", False, "14",
|
|
"Editor font size in pixels. Zero inherits."),
|
|
field("terminal_font_size", "body", "integer", False, "13",
|
|
"Terminal font size in pixels. Zero inherits."),
|
|
field("zoom_level", "body", "integer", False, "0",
|
|
"Window zoom, -5 to 5. Send -99 to inherit."),
|
|
field("boot_agent", "body", "string", False, "dpc",
|
|
"dpc or none."),
|
|
field("boot_shell", "body", "integer", False, "1",
|
|
"1 opens a shell on boot, 0 skips it, -1 inherits."),
|
|
field("window_mode", "body", "string", False, "tab",
|
|
"tab, window or fullscreen."),
|
|
field("window_width", "body", "integer", False, "1600",
|
|
"Editor window width in pixels. Zero inherits."),
|
|
field("window_height", "body", "integer", False, "1000",
|
|
"Editor window height in pixels. Zero inherits."),
|
|
field("reset", "body", "boolean", False, "false",
|
|
"Drop every preference and fall back to the site defaults."),
|
|
],
|
|
sample_response={
|
|
"ok": True,
|
|
"redirect": "/projects/my-project/workspace",
|
|
"data": {"restart_required": True},
|
|
},
|
|
),
|
|
endpoint(
|
|
id="workspace-tunnels-list",
|
|
method="GET",
|
|
path="/projects/{slug}/workspace/tunnels",
|
|
title="List tunnels",
|
|
summary="Every public tunnel published by this workspace.",
|
|
auth="user",
|
|
params=[
|
|
field("slug", "path", "string", True, "my-project", "Project slug or uid."),
|
|
],
|
|
sample_response={
|
|
"tunnels": [
|
|
{
|
|
"uid": "TUNNEL_UID",
|
|
"hostname": "8080-brave-otter.tunnel.pravda.education",
|
|
"label": "web",
|
|
"container_port": 8080,
|
|
"status": "active",
|
|
"cert_status": "valid",
|
|
"request_count": 12,
|
|
"bytes_out": 40960,
|
|
}
|
|
]
|
|
},
|
|
),
|
|
endpoint(
|
|
id="workspace-tunnel-create",
|
|
method="POST",
|
|
path="/projects/{slug}/workspace/tunnels",
|
|
title="Create tunnel",
|
|
summary=(
|
|
"Publish a container port on a public HTTPS hostname. The URL is public "
|
|
"and unauthenticated. Refused past the tunnel limit."
|
|
),
|
|
auth="user",
|
|
params=[
|
|
field("slug", "path", "string", True, "my-project", "Project slug or uid."),
|
|
field("container_port", "body", "integer", True, 8080, "Port inside the container."),
|
|
field("label", "body", "string", False, "web", "Human label."),
|
|
],
|
|
sample_response={
|
|
"ok": True,
|
|
"data": {
|
|
"uid": "TUNNEL_UID",
|
|
"hostname": "8080-brave-otter.tunnel.pravda.education",
|
|
"status": "pending",
|
|
},
|
|
},
|
|
),
|
|
endpoint(
|
|
id="workspace-tunnel-delete",
|
|
method="POST",
|
|
path="/projects/{slug}/workspace/tunnels/{uid}/delete",
|
|
title="Delete tunnel",
|
|
summary="Remove a tunnel. The public URL stops serving immediately.",
|
|
auth="user",
|
|
params=[
|
|
field("slug", "path", "string", True, "my-project", "Project slug or uid."),
|
|
field("uid", "path", "string", True, "TUNNEL_UID", "Tunnel uid."),
|
|
],
|
|
sample_response={"ok": True, "redirect": "/projects/my-project/workspace"},
|
|
),
|
|
],
|
|
}
|