prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN 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.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `distributed/dashboard/scheduler.py`
  Content:
  ```
  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 FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
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"}], "after_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\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\n\ntemplate_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\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", "path": "distributed/dashboard/scheduler.py"}]}