prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Drop down tile to reveal "secret" dashboards
  We're accumulating a lot of _secret_ dashboard pages https://github.com/dask/distributed/blob/c2557938e6c4175534031cba5ca5ac9d2cdc95f7/distributed/dashboard/scheduler.py#L82-L119
  although most are not easily accessible from the UI. Most of the pages are not useful for the ordinary user and are only relevant for specific edge cases or debugging. hence, it makes sense that they are not promoted as a top-level dashboard page.
  
  However, at least for debugging purposes, I would really appreciate if these pages were a bit easier to navigate. In particular I'm looking for a way which doesn't require me to know the exact endpoint for an individual plot and requires me to type it into my browser.
  
  I would propose to add a drop down menu / button which can be used to browse all _hidden_ dashboard pages.
  
  Disclaimer: I can't implement this. I barely know what bokeh is.
  
  </issue>
  <code>
  [start of distributed/dashboard/scheduler.py]
  1 from urllib.parse import urljoin
  2 
  3 from tornado import web
  4 from tornado.ioloop import IOLoop
  5 
  6 try:
  7     import numpy as np
  8 except ImportError:
  9     np = False
  10 
  11 from .components.nvml import gpu_doc  # noqa: 1708
  12 from .components.nvml import NVML_ENABLED, gpu_memory_doc, gpu_utilization_doc
  13 from .components.scheduler import (
  14     AggregateAction,
  15     BandwidthTypes,
  16     BandwidthWorkers,
  17     ComputePerKey,
  18     CurrentLoad,
  19     MemoryByKey,
  20     NBytes,
  21     NBytesCluster,
  22     Occupancy,
  23     SystemMonitor,
  24     TaskGraph,
  25     TaskGroupGraph,
  26     TaskProgress,
  27     TaskStream,
  28     WorkerTable,
  29     events_doc,
  30     graph_doc,
  31     individual_doc,
  32     individual_profile_doc,
  33     individual_profile_server_doc,
  34     profile_doc,
  35     profile_server_doc,
  36     status_doc,
  37     stealing_doc,
  38     systemmonitor_doc,
  39     tasks_doc,
  40     tg_graph_doc,
  41     workers_doc,
  42 )
  43 from .core import BokehApplication
  44 from .worker import counters_doc
  45 
  46 template_variables = {
  47     "pages": [
  48         "status",
  49         "workers",
  50         "tasks",
  51         "system",
  52         "profile",
  53         "graph",
  54         "groups",
  55         "info",
  56     ]
  57 }
  58 
  59 if NVML_ENABLED:
  60     template_variables["pages"].insert(4, "gpu")
  61 
  62 
  63 def connect(application, http_server, scheduler, prefix=""):
  64     bokeh_app = BokehApplication(
  65         applications, scheduler, prefix=prefix, template_variables=template_variables
  66     )
  67     application.add_application(bokeh_app)
  68     bokeh_app.initialize(IOLoop.current())
  69 
  70     bokeh_app.add_handlers(
  71         r".*",
  72         [
  73             (
  74                 r"/",
  75                 web.RedirectHandler,
  76                 {"url": urljoin((prefix or "").strip("/") + "/", r"status")},
  77             )
  78         ],
  79     )
  80 
  81 
  82 applications = {
  83     "/system": systemmonitor_doc,
  84     "/stealing": stealing_doc,
  85     "/workers": workers_doc,
  86     "/events": events_doc,
  87     "/counters": counters_doc,
  88     "/tasks": tasks_doc,
  89     "/status": status_doc,
  90     "/profile": profile_doc,
  91     "/profile-server": profile_server_doc,
  92     "/graph": graph_doc,
  93     "/groups": tg_graph_doc,
  94     "/gpu": gpu_doc,
  95     "/individual-task-stream": individual_doc(
  96         TaskStream, 100, n_rectangles=1000, clear_interval="10s"
  97     ),
  98     "/individual-progress": individual_doc(TaskProgress, 100, height=160),
  99     "/individual-graph": individual_doc(TaskGraph, 200),
  100     "/individual-groups": individual_doc(TaskGroupGraph, 200),
  101     "/individual-nbytes": individual_doc(NBytes, 100),
  102     "/individual-nbytes-cluster": individual_doc(NBytesCluster, 100),
  103     "/individual-cpu": individual_doc(CurrentLoad, 100, fig_attr="cpu_figure"),
  104     "/individual-nprocessing": individual_doc(
  105         CurrentLoad, 100, fig_attr="processing_figure"
  106     ),
  107     "/individual-occupancy": individual_doc(Occupancy, 100),
  108     "/individual-workers": individual_doc(WorkerTable, 500),
  109     "/individual-bandwidth-types": individual_doc(BandwidthTypes, 500),
  110     "/individual-bandwidth-workers": individual_doc(BandwidthWorkers, 500),
  111     "/individual-memory-by-key": individual_doc(MemoryByKey, 500),
  112     "/individual-compute-time-per-key": individual_doc(ComputePerKey, 500),
  113     "/individual-aggregate-time-per-action": individual_doc(AggregateAction, 500),
  114     "/individual-scheduler-system": individual_doc(SystemMonitor, 500),
  115     "/individual-profile": individual_profile_doc,
  116     "/individual-profile-server": individual_profile_server_doc,
  117     "/individual-gpu-memory": gpu_memory_doc,
  118     "/individual-gpu-utilization": gpu_utilization_doc,
  119 }
  120
  [end of distributed/dashboard/scheduler.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/distributed/dashboard/scheduler.py b/distributed/dashboard/scheduler.py
  --- a/distributed/dashboard/scheduler.py
  +++ b/distributed/dashboard/scheduler.py
  @@ -43,42 +43,6 @@
   from .core import BokehApplication
   from .worker import counters_doc
   
  -template_variables = {
  -    "pages": [
  -        "status",
  -        "workers",
  -        "tasks",
  -        "system",
  -        "profile",
  -        "graph",
  -        "groups",
  -        "info",
  -    ]
  -}
  -
  -if NVML_ENABLED:
  -    template_variables["pages"].insert(4, "gpu")
  -
  -
  -def connect(application, http_server, scheduler, prefix=""):
  -    bokeh_app = BokehApplication(
  -        applications, scheduler, prefix=prefix, template_variables=template_variables
  -    )
  -    application.add_application(bokeh_app)
  -    bokeh_app.initialize(IOLoop.current())
  -
  -    bokeh_app.add_handlers(
  -        r".*",
  -        [
  -            (
  -                r"/",
  -                web.RedirectHandler,
  -                {"url": urljoin((prefix or "").strip("/") + "/", r"status")},
  -            )
  -        ],
  -    )
  -
  -
   applications = {
       "/system": systemmonitor_doc,
       "/stealing": stealing_doc,
  @@ -117,3 +81,40 @@
       "/individual-gpu-memory": gpu_memory_doc,
       "/individual-gpu-utilization": gpu_utilization_doc,
   }
  +
  +
  +template_variables = {
  +    "pages": [
  +        "status",
  +        "workers",
  +        "tasks",
  +        "system",
  +        "profile",
  +        "graph",
  +        "groups",
  +        "info",
  +    ],
  +    "plots": [x.replace("/", "") for x in applications if "individual" in x],
  +}
  +
  +if NVML_ENABLED:
  +    template_variables["pages"].insert(4, "gpu")
  +
  +
  +def connect(application, http_server, scheduler, prefix=""):
  +    bokeh_app = BokehApplication(
  +        applications, scheduler, prefix=prefix, template_variables=template_variables
  +    )
  +    application.add_application(bokeh_app)
  +    bokeh_app.initialize(IOLoop.current())
  +
  +    bokeh_app.add_handlers(
  +        r".*",
  +        [
  +            (
  +                r"/",
  +                web.RedirectHandler,
  +                {"url": urljoin((prefix or "").strip("/") + "/", r"status")},
  +            )
  +        ],
  +    )
  
verification_info: {"golden_diff": "diff --git a/distributed/dashboard/scheduler.py b/distributed/dashboard/scheduler.py\n--- a/distributed/dashboard/scheduler.py\n+++ b/distributed/dashboard/scheduler.py\n@@ -43,42 +43,6 @@\n from .core import BokehApplication\n from .worker import counters_doc\n \n-template_variables = {\n-    \"pages\": [\n-        \"status\",\n-        \"workers\",\n-        \"tasks\",\n-        \"system\",\n-        \"profile\",\n-        \"graph\",\n-        \"groups\",\n-        \"info\",\n-    ]\n-}\n-\n-if NVML_ENABLED:\n-    template_variables[\"pages\"].insert(4, \"gpu\")\n-\n-\n-def connect(application, http_server, scheduler, prefix=\"\"):\n-    bokeh_app = BokehApplication(\n-        applications, scheduler, prefix=prefix, template_variables=template_variables\n-    )\n-    application.add_application(bokeh_app)\n-    bokeh_app.initialize(IOLoop.current())\n-\n-    bokeh_app.add_handlers(\n-        r\".*\",\n-        [\n-            (\n-                r\"/\",\n-                web.RedirectHandler,\n-                {\"url\": urljoin((prefix or \"\").strip(\"/\") + \"/\", r\"status\")},\n-            )\n-        ],\n-    )\n-\n-\n applications = {\n     \"/system\": systemmonitor_doc,\n     \"/stealing\": stealing_doc,\n@@ -117,3 +81,40 @@\n     \"/individual-gpu-memory\": gpu_memory_doc,\n     \"/individual-gpu-utilization\": gpu_utilization_doc,\n }\n+\n+\n+template_variables = {\n+    \"pages\": [\n+        \"status\",\n+        \"workers\",\n+        \"tasks\",\n+        \"system\",\n+        \"profile\",\n+        \"graph\",\n+        \"groups\",\n+        \"info\",\n+    ],\n+    \"plots\": [x.replace(\"/\", \"\") for x in applications if \"individual\" in x],\n+}\n+\n+if NVML_ENABLED:\n+    template_variables[\"pages\"].insert(4, \"gpu\")\n+\n+\n+def connect(application, http_server, scheduler, prefix=\"\"):\n+    bokeh_app = BokehApplication(\n+        applications, scheduler, prefix=prefix, template_variables=template_variables\n+    )\n+    application.add_application(bokeh_app)\n+    bokeh_app.initialize(IOLoop.current())\n+\n+    bokeh_app.add_handlers(\n+        r\".*\",\n+        [\n+            (\n+                r\"/\",\n+                web.RedirectHandler,\n+                {\"url\": urljoin((prefix or \"\").strip(\"/\") + \"/\", r\"status\")},\n+            )\n+        ],\n+    )\n", "issue": "Drop down tile to reveal \"secret\" dashboards\nWe're accumulating a lot of _secret_ dashboard pages https://github.com/dask/distributed/blob/c2557938e6c4175534031cba5ca5ac9d2cdc95f7/distributed/dashboard/scheduler.py#L82-L119\r\nalthough most are not easily accessible from the UI. Most of the pages are not useful for the ordinary user and are only relevant for specific edge cases or debugging. hence, it makes sense that they are not promoted as a top-level dashboard page.\r\n\r\nHowever, at least for debugging purposes, I would really appreciate if these pages were a bit easier to navigate. In particular I'm looking for a way which doesn't require me to know the exact endpoint for an individual plot and requires me to type it into my browser.\r\n\r\nI would propose to add a drop down menu / button which can be used to browse all _hidden_ dashboard pages.\r\n\r\nDisclaimer: I can't implement this. I barely know what bokeh is.\n", "before_files": [{"content": "from urllib.parse import urljoin\n\nfrom tornado import web\nfrom tornado.ioloop import IOLoop\n\ntry:\n    import numpy as np\nexcept ImportError:\n    np = False\n\nfrom .components.nvml import gpu_doc  # noqa: 1708\nfrom .components.nvml import NVML_ENABLED, gpu_memory_doc, gpu_utilization_doc\nfrom .components.scheduler import (\n    AggregateAction,\n    BandwidthTypes,\n    BandwidthWorkers,\n    ComputePerKey,\n    CurrentLoad,\n    MemoryByKey,\n    NBytes,\n    NBytesCluster,\n    Occupancy,\n    SystemMonitor,\n    TaskGraph,\n    TaskGroupGraph,\n    TaskProgress,\n    TaskStream,\n    WorkerTable,\n    events_doc,\n    graph_doc,\n    individual_doc,\n    individual_profile_doc,\n    individual_profile_server_doc,\n    profile_doc,\n    profile_server_doc,\n    status_doc,\n    stealing_doc,\n    systemmonitor_doc,\n    tasks_doc,\n    tg_graph_doc,\n    workers_doc,\n)\nfrom .core import BokehApplication\nfrom .worker import counters_doc\n\ntemplate_variables = {\n    \"pages\": [\n        \"status\",\n        \"workers\",\n        \"tasks\",\n        \"system\",\n        \"profile\",\n        \"graph\",\n        \"groups\",\n        \"info\",\n    ]\n}\n\nif NVML_ENABLED:\n    template_variables[\"pages\"].insert(4, \"gpu\")\n\n\ndef connect(application, http_server, scheduler, prefix=\"\"):\n    bokeh_app = BokehApplication(\n        applications, scheduler, prefix=prefix, template_variables=template_variables\n    )\n    application.add_application(bokeh_app)\n    bokeh_app.initialize(IOLoop.current())\n\n    bokeh_app.add_handlers(\n        r\".*\",\n        [\n            (\n                r\"/\",\n                web.RedirectHandler,\n                {\"url\": urljoin((prefix or \"\").strip(\"/\") + \"/\", r\"status\")},\n            )\n        ],\n    )\n\n\napplications = {\n    \"/system\": systemmonitor_doc,\n    \"/stealing\": stealing_doc,\n    \"/workers\": workers_doc,\n    \"/events\": events_doc,\n    \"/counters\": counters_doc,\n    \"/tasks\": tasks_doc,\n    \"/status\": status_doc,\n    \"/profile\": profile_doc,\n    \"/profile-server\": profile_server_doc,\n    \"/graph\": graph_doc,\n    \"/groups\": tg_graph_doc,\n    \"/gpu\": gpu_doc,\n    \"/individual-task-stream\": individual_doc(\n        TaskStream, 100, n_rectangles=1000, clear_interval=\"10s\"\n    ),\n    \"/individual-progress\": individual_doc(TaskProgress, 100, height=160),\n    \"/individual-graph\": individual_doc(TaskGraph, 200),\n    \"/individual-groups\": individual_doc(TaskGroupGraph, 200),\n    \"/individual-nbytes\": individual_doc(NBytes, 100),\n    \"/individual-nbytes-cluster\": individual_doc(NBytesCluster, 100),\n    \"/individual-cpu\": individual_doc(CurrentLoad, 100, fig_attr=\"cpu_figure\"),\n    \"/individual-nprocessing\": individual_doc(\n        CurrentLoad, 100, fig_attr=\"processing_figure\"\n    ),\n    \"/individual-occupancy\": individual_doc(Occupancy, 100),\n    \"/individual-workers\": individual_doc(WorkerTable, 500),\n    \"/individual-bandwidth-types\": individual_doc(BandwidthTypes, 500),\n    \"/individual-bandwidth-workers\": individual_doc(BandwidthWorkers, 500),\n    \"/individual-memory-by-key\": individual_doc(MemoryByKey, 500),\n    \"/individual-compute-time-per-key\": individual_doc(ComputePerKey, 500),\n    \"/individual-aggregate-time-per-action\": individual_doc(AggregateAction, 500),\n    \"/individual-scheduler-system\": individual_doc(SystemMonitor, 500),\n    \"/individual-profile\": individual_profile_doc,\n    \"/individual-profile-server\": individual_profile_server_doc,\n    \"/individual-gpu-memory\": gpu_memory_doc,\n    \"/individual-gpu-utilization\": gpu_utilization_doc,\n}\n", "path": "distributed/dashboard/scheduler.py"}]}