Просмотр исходного кода

docs: Standardize on "Server Diagnostics", update many screenshots

jamesread 1 месяц назад
Родитель
Сommit
5b1a29db7f
100 измененных файлов с 995 добавлено и 35 удалено
  1. 11 30
      .github/ISSUE_TEMPLATE/support_request.md
  2. 3 3
      .gitignore
  3. BIN
      docs/modules/ROOT/images/action-confirmation.png
  4. 2 0
      docs/modules/ROOT/images/action_customization/max-rate/.gitignore
  5. 2 0
      docs/modules/ROOT/images/action_customization/max-rate/Makefile
  6. 14 0
      docs/modules/ROOT/images/action_customization/max-rate/config.yaml
  7. BIN
      docs/modules/ROOT/images/action_customization/max-rate/maxRate.png
  8. 11 0
      docs/modules/ROOT/images/action_customization/max-rate/screenshots.ini
  9. 92 0
      docs/modules/ROOT/images/action_customization/max-rate/setup_max_rate.py
  10. 2 0
      docs/modules/ROOT/images/action_customization/popup-output-only/.gitignore
  11. 2 0
      docs/modules/ROOT/images/action_customization/popup-output-only/Makefile
  12. 16 0
      docs/modules/ROOT/images/action_customization/popup-output-only/config.yaml
  13. BIN
      docs/modules/ROOT/images/action_customization/popup-output-only/popupOutputOnly.png
  14. 11 0
      docs/modules/ROOT/images/action_customization/popup-output-only/screenshots.ini
  15. 47 0
      docs/modules/ROOT/images/action_customization/popup-output-only/setup_popup_output_only.py
  16. 2 0
      docs/modules/ROOT/images/advanced_configuration/diagnostics/.gitignore
  17. 2 0
      docs/modules/ROOT/images/advanced_configuration/diagnostics/Makefile
  18. 11 0
      docs/modules/ROOT/images/advanced_configuration/diagnostics/config.yaml
  19. BIN
      docs/modules/ROOT/images/advanced_configuration/diagnostics/diagnostics.png
  20. 11 0
      docs/modules/ROOT/images/advanced_configuration/diagnostics/screenshots.ini
  21. 54 0
      docs/modules/ROOT/images/advanced_configuration/diagnostics/setup_diagnostics.py
  22. 2 0
      docs/modules/ROOT/images/advanced_configuration/webui/hide-navigation/.gitignore
  23. 2 0
      docs/modules/ROOT/images/advanced_configuration/webui/hide-navigation/Makefile
  24. 48 0
      docs/modules/ROOT/images/advanced_configuration/webui/hide-navigation/config.yaml
  25. BIN
      docs/modules/ROOT/images/advanced_configuration/webui/hide-navigation/hide-navigation.png
  26. 11 0
      docs/modules/ROOT/images/advanced_configuration/webui/hide-navigation/screenshots.ini
  27. 20 0
      docs/modules/ROOT/images/advanced_configuration/webui/hide-navigation/setup_hide_navigation.py
  28. 2 0
      docs/modules/ROOT/images/advanced_configuration/webui/page-title/.gitignore
  29. 2 0
      docs/modules/ROOT/images/advanced_configuration/webui/page-title/Makefile
  30. 19 0
      docs/modules/ROOT/images/advanced_configuration/webui/page-title/config.yaml
  31. BIN
      docs/modules/ROOT/images/advanced_configuration/webui/page-title/page-title.png
  32. 11 0
      docs/modules/ROOT/images/advanced_configuration/webui/page-title/screenshots.ini
  33. 20 0
      docs/modules/ROOT/images/advanced_configuration/webui/page-title/setup_page_title.py
  34. 2 0
      docs/modules/ROOT/images/advanced_configuration/webui/sidebar/.gitignore
  35. 2 0
      docs/modules/ROOT/images/advanced_configuration/webui/sidebar/Makefile
  36. 30 0
      docs/modules/ROOT/images/advanced_configuration/webui/sidebar/config.yaml
  37. 11 0
      docs/modules/ROOT/images/advanced_configuration/webui/sidebar/screenshots.ini
  38. 44 0
      docs/modules/ROOT/images/advanced_configuration/webui/sidebar/setup_sidebar.py
  39. BIN
      docs/modules/ROOT/images/advanced_configuration/webui/sidebar/sidebar.png
  40. 2 0
      docs/modules/ROOT/images/advanced_configuration/webui/topbar/.gitignore
  41. 2 0
      docs/modules/ROOT/images/advanced_configuration/webui/topbar/Makefile
  42. 33 0
      docs/modules/ROOT/images/advanced_configuration/webui/topbar/config.yaml
  43. 11 0
      docs/modules/ROOT/images/advanced_configuration/webui/topbar/screenshots.ini
  44. 58 0
      docs/modules/ROOT/images/advanced_configuration/webui/topbar/setup_topbar.py
  45. BIN
      docs/modules/ROOT/images/advanced_configuration/webui/topbar/topbar.png
  46. 2 0
      docs/modules/ROOT/images/advanced_configuration/webui/with-navigation/.gitignore
  47. 2 0
      docs/modules/ROOT/images/advanced_configuration/webui/with-navigation/Makefile
  48. 47 0
      docs/modules/ROOT/images/advanced_configuration/webui/with-navigation/config.yaml
  49. 11 0
      docs/modules/ROOT/images/advanced_configuration/webui/with-navigation/screenshots.ini
  50. 23 0
      docs/modules/ROOT/images/advanced_configuration/webui/with-navigation/setup_with_navigation.py
  51. BIN
      docs/modules/ROOT/images/advanced_configuration/webui/with-navigation/with-navigation.png
  52. BIN
      docs/modules/ROOT/images/args-multiline-text.png
  53. 2 0
      docs/modules/ROOT/images/args/confirmation/.gitignore
  54. 2 0
      docs/modules/ROOT/images/args/confirmation/Makefile
  55. 14 0
      docs/modules/ROOT/images/args/confirmation/config.yaml
  56. BIN
      docs/modules/ROOT/images/args/confirmation/confirmation.png
  57. 11 0
      docs/modules/ROOT/images/args/confirmation/screenshots.ini
  58. 25 0
      docs/modules/ROOT/images/args/confirmation/setup_confirmation.py
  59. BIN
      docs/modules/ROOT/images/args/input/args1.png
  60. BIN
      docs/modules/ROOT/images/args/input/args2.png
  61. BIN
      docs/modules/ROOT/images/args/input/args3.png
  62. 1 0
      docs/modules/ROOT/images/args/input/screenshots.ini
  63. 11 1
      docs/modules/ROOT/images/args/input/setup_args3.py
  64. 2 0
      docs/modules/ROOT/images/args/textarea/.gitignore
  65. 2 0
      docs/modules/ROOT/images/args/textarea/Makefile
  66. 17 0
      docs/modules/ROOT/images/args/textarea/config.yaml
  67. BIN
      docs/modules/ROOT/images/args/textarea/multiline-text.png
  68. 11 0
      docs/modules/ROOT/images/args/textarea/screenshots.ini
  69. 27 0
      docs/modules/ROOT/images/args/textarea/setup_textarea.py
  70. 2 0
      docs/modules/ROOT/images/dashboards/fieldsets/.gitignore
  71. 2 0
      docs/modules/ROOT/images/dashboards/fieldsets/Makefile
  72. 25 0
      docs/modules/ROOT/images/dashboards/fieldsets/config.yaml
  73. BIN
      docs/modules/ROOT/images/dashboards/fieldsets/fieldset.png
  74. 11 0
      docs/modules/ROOT/images/dashboards/fieldsets/screenshots.ini
  75. 35 0
      docs/modules/ROOT/images/dashboards/fieldsets/setup_fieldset.py
  76. 2 0
      docs/modules/ROOT/images/dashboards/folders/.gitignore
  77. 2 0
      docs/modules/ROOT/images/dashboards/folders/Makefile
  78. 33 0
      docs/modules/ROOT/images/dashboards/folders/config.yaml
  79. BIN
      docs/modules/ROOT/images/dashboards/folders/folders.png
  80. 11 0
      docs/modules/ROOT/images/dashboards/folders/screenshots.ini
  81. 36 0
      docs/modules/ROOT/images/dashboards/folders/setup_folders.py
  82. BIN
      docs/modules/ROOT/images/dashboards/intro/preview.png
  83. 1 1
      docs/modules/ROOT/images/dashboards/intro/screenshots.ini
  84. BIN
      docs/modules/ROOT/images/defaultUiHideNav.png
  85. BIN
      docs/modules/ROOT/images/defaultUiWithNav.png
  86. BIN
      docs/modules/ROOT/images/diagnostics.png
  87. BIN
      docs/modules/ROOT/images/fieldset.png
  88. BIN
      docs/modules/ROOT/images/folders.png
  89. BIN
      docs/modules/ROOT/images/gitops.png
  90. 0 0
      docs/modules/ROOT/images/integrations/hass/hacs-custom-repo.png
  91. 0 0
      docs/modules/ROOT/images/integrations/hass/hacs-download.png
  92. 0 0
      docs/modules/ROOT/images/integrations/hass/hacs-dropdown.png
  93. 0 0
      docs/modules/ROOT/images/integrations/hass/hacs-search.png
  94. 0 0
      docs/modules/ROOT/images/integrations/hass/hass-add-integration.png
  95. 0 0
      docs/modules/ROOT/images/integrations/hass/hass-buttons.png
  96. 0 0
      docs/modules/ROOT/images/integrations/hass/hass-configure-integration.png
  97. 0 0
      docs/modules/ROOT/images/integrations/hass/hass-devices-and-services.png
  98. 0 0
      docs/modules/ROOT/images/integrations/hass/hassButtonSetup.png
  99. 0 0
      docs/modules/ROOT/images/integrations/hass/hassConfigYaml.png
  100. 0 0
      docs/modules/ROOT/images/integrations/hass/hassFileEditor.png

+ 11 - 30
.github/ISSUE_TEMPLATE/support_request.md

@@ -1,48 +1,29 @@
 ---
 name: Support request
-about: Need some help? Got an error message?
-title: ""
-type: support
-labels:
-  - "waiting-on-developer"
+about: Ask for help with OliveTin
+title: ''
+labels: ''
 assignees: ''
 
 ---
 
-**What seems to be the problem?!**
+**What is the problem you are having?**
 
-If you are getting an error message, then please copy/paste, or better, provide
-a screenshot to show us exactly what is wrong.
 
-**Can you provide a sosreport?**
+**What OliveTin version are you running?**
 
-A sosreport really helps us to help you, by providing critical information about your install. If you can generate a sosreport, please copy and paste the output here.
 
-How to generate a sosreport: https://docs.olivetin.app/sosreport.html
+**Can you provide Server Diagnostics?**
 
-**What package/file/container did you use to install OliveTin?**
+Server Diagnostics really helps us to help you, by providing critical information about your install. If you can generate Server Diagnostics, please copy and paste the output here.
 
-eg: OliveTin-1234-x86_64.rpm
-eg: Container from Dockerhub - please include the version number
+How to generate Server Diagnostics: https://docs.olivetin.app/troubleshooting/server-diagnostics.html
 
-**Your config.yaml**
 
-```
-Please copy-paste your config.yaml here
+**What is your config.yaml?**
 
-You don't need to include anything under "actions:" unless that is where your
-error probably is.
-```
 
-**OliveTin logs**
+**What are the OliveTin service logs showing?**
 
-If possible, please copy and paste your OliveTin logs from when the error happened.
 
-**Screenshot of WebDeveloper console logs**
-
-If you know how, and if you think it's relevant, a screenshot of the
-WebDeveloper console from when you clicked a button is often really helpful.
-
-**Anything else?**
-
-Add any other context about the problem here.
+**Screenshots (if appropriate)**

+ 3 - 3
.gitignore

@@ -18,12 +18,12 @@ integration-tests/flakey-test-runs.jsonl
 service/flakey-test-runs.log
 service/flakey-test-runs.jsonl
 .vscode/
-webui/
+/webui/
 server.log
 OliveTin
 integration-tests/configs/authRequireGuestsToLogin/sessions.yaml
-webui
-webui.dev
+/webui
+/webui.dev
 sessions.yaml
 docs/build/
 build/

BIN
docs/modules/ROOT/images/action-confirmation.png


+ 2 - 0
docs/modules/ROOT/images/action_customization/max-rate/.gitignore

@@ -0,0 +1,2 @@
+custom-webui/
+__pycache__/

+ 2 - 0
docs/modules/ROOT/images/action_customization/max-rate/Makefile

@@ -0,0 +1,2 @@
+CONFIGDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+include ../../screenshots.mk

+ 14 - 0
docs/modules/ROOT/images/action_customization/max-rate/config.yaml

@@ -0,0 +1,14 @@
+---
+listenAddressSingleHTTPFrontend: 0.0.0.0:11337
+
+logLevel: "WARN"
+checkForUpdates: false
+showFooter: false
+
+actions:
+  - title: date
+    shell: date
+    icon: clock
+    maxRate:
+      - limit: 3
+        duration: 5m

BIN
docs/modules/ROOT/images/action_customization/max-rate/maxRate.png


+ 11 - 0
docs/modules/ROOT/images/action_customization/max-rate/screenshots.ini

@@ -0,0 +1,11 @@
+[DEFAULT]
+base_url = http://localhost:11337/
+dir = .
+width = 980
+height = 620
+post_script_sleep = 0.5
+
+[max-rate]
+url = .
+name = maxRate
+script = setup_max_rate.py

+ 92 - 0
docs/modules/ROOT/images/action_customization/max-rate/setup_max_rate.py

@@ -0,0 +1,92 @@
+#!/usr/bin/env python3
+"""Show blocked rate-limit log entries for the date action."""
+
+import time
+
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+
+_START_ACTION_REPEATEDLY_JS = """
+const done = arguments[arguments.length - 1];
+const title = arguments[0];
+const count = arguments[1];
+
+function bindingIdForTitle(actionTitle) {
+  const button = document.querySelector('[title="' + actionTitle + '"]');
+  if (!button) {
+    throw new Error('Action button not found: ' + actionTitle);
+  }
+  return button.closest('.action-button').id.replace('actionButton-', '');
+}
+
+function uniqueTrackingId() {
+  if (window.isSecureContext && window.crypto?.randomUUID) {
+    return window.crypto.randomUUID();
+  }
+  return 'doc-screenshot-' + Date.now() + '-' + Math.random();
+}
+
+async function startAndWait(actionTitle) {
+  const bindingId = bindingIdForTitle(actionTitle);
+  const trackingId = uniqueTrackingId();
+  const response = await window.client.startAction({
+    bindingId,
+    arguments: [],
+    uniqueTrackingId: trackingId,
+  });
+  const executionTrackingId = response.executionTrackingId || trackingId;
+
+  while (true) {
+    const result = await window.client.executionStatus({
+      executionTrackingId,
+    });
+    if (result.logEntry?.executionFinished) {
+      return result.logEntry;
+    }
+    await new Promise((resolve) => setTimeout(resolve, 100));
+  }
+}
+
+async function startRepeatedly(actionTitle, runs) {
+  for (let i = 0; i < runs; i++) {
+    await startAndWait(actionTitle);
+  }
+}
+
+startRepeatedly(title, count).then(() => done(true)).catch((err) => done(String(err)));
+"""
+
+
+def _wait_for_dashboard(driver, timeout=15):
+    WebDriverWait(driver, timeout).until(
+        lambda d: bool(d.find_element(By.TAG_NAME, "body").get_attribute("loaded-dashboard"))
+    )
+    WebDriverWait(driver, timeout).until(
+        lambda d: d.execute_script("return !!window.client")
+    )
+
+
+def _wait_for_rate_limited_logs(driver, timeout=20):
+    def ready(d):
+        try:
+            rows = d.find_elements(By.CSS_SELECTOR, ".logs-table tbody tr")
+            blocked = d.find_elements(By.CSS_SELECTOR, ".logs-table .status-blocked")
+            completed = d.find_elements(By.CSS_SELECTOR, ".logs-table .status-success")
+        except Exception:
+            return False
+        return len(rows) >= 5 and len(blocked) >= 2 and len(completed) >= 3
+
+    WebDriverWait(driver, timeout).until(ready)
+
+
+def run(driver):
+    _wait_for_dashboard(driver)
+
+    driver.execute_async_script(_START_ACTION_REPEATEDLY_JS, "date", 5)
+
+    time.sleep(1)
+
+    driver.execute_script("window.location.href = '/logs'")
+    _wait_for_rate_limited_logs(driver)
+
+    time.sleep(0.2)

+ 2 - 0
docs/modules/ROOT/images/action_customization/popup-output-only/.gitignore

@@ -0,0 +1,2 @@
+custom-webui/
+__pycache__/

+ 2 - 0
docs/modules/ROOT/images/action_customization/popup-output-only/Makefile

@@ -0,0 +1,2 @@
+CONFIGDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+include ../../screenshots.mk

+ 16 - 0
docs/modules/ROOT/images/action_customization/popup-output-only/config.yaml

@@ -0,0 +1,16 @@
+---
+listenAddressSingleHTTPFrontend: 0.0.0.0:11337
+
+logLevel: "WARN"
+checkForUpdates: false
+showFooter: false
+
+actions:
+  - title: Check disk space
+    icon: disk
+    onclick: execution-dialog
+    shell: |
+      echo "Filesystem      Size  Used Avail Use% Mounted on"
+      echo "/dev/mapper/fedora_mindstorm-root   99G   82G   12G  88% /"
+      echo "Filesystem      Size  Used Avail Use% Mounted on"
+      echo "/dev/mapper/fedora_mindstorm-root   99G   82G   12G  88% /"

BIN
docs/modules/ROOT/images/action_customization/popup-output-only/popupOutputOnly.png


+ 11 - 0
docs/modules/ROOT/images/action_customization/popup-output-only/screenshots.ini

@@ -0,0 +1,11 @@
+[DEFAULT]
+base_url = http://localhost:11337/
+dir = .
+width = 900
+height = 620
+post_script_sleep = 0.5
+
+[popup-output-only]
+url = .
+name = popupOutputOnly
+script = setup_popup_output_only.py

+ 47 - 0
docs/modules/ROOT/images/action_customization/popup-output-only/setup_popup_output_only.py

@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+"""Open the execution dialog for Check disk space."""
+
+import time
+
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+
+
+def _wait_for_body_attr(driver, attr, timeout=15):
+    WebDriverWait(driver, timeout).until(
+        lambda d: bool(d.find_element(By.TAG_NAME, "body").get_attribute(attr))
+    )
+
+
+def _wait_for_logs_page(driver, timeout=15):
+    WebDriverWait(driver, timeout).until(
+        lambda d: "/logs/" in d.current_url and not d.current_url.rstrip("/").endswith("/logs")
+    )
+
+
+def _wait_for_execution_complete(driver, timeout=15):
+    def finished(d):
+        try:
+            status = d.find_element(By.CSS_SELECTOR, ".execution-dialog-status").text
+        except Exception:
+            return False
+        return "Still running" not in status and "Queued" not in status
+
+    WebDriverWait(driver, timeout).until(finished)
+
+
+def run(driver):
+    _wait_for_body_attr(driver, "loaded-dashboard")
+
+    driver.find_element(By.CSS_SELECTOR, '[title="Check disk space"]').click()
+
+    _wait_for_logs_page(driver)
+    _wait_for_execution_complete(driver)
+
+    WebDriverWait(driver, 15).until(
+        lambda d: "fedora_mindstorm-root" in d.find_element(
+            By.CSS_SELECTOR, "#execution-results-popup .xterm-rows"
+        ).text
+    )
+
+    time.sleep(0.2)

+ 2 - 0
docs/modules/ROOT/images/advanced_configuration/diagnostics/.gitignore

@@ -0,0 +1,2 @@
+custom-webui/
+__pycache__/

+ 2 - 0
docs/modules/ROOT/images/advanced_configuration/diagnostics/Makefile

@@ -0,0 +1,2 @@
+CONFIGDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+include ../../screenshots.mk

+ 11 - 0
docs/modules/ROOT/images/advanced_configuration/diagnostics/config.yaml

@@ -0,0 +1,11 @@
+---
+listenAddressSingleHTTPFrontend: 0.0.0.0:11337
+
+logLevel: "WARN"
+checkForUpdates: false
+showFooter: false
+
+actions:
+  - title: date
+    icon: clock
+    shell: date

BIN
docs/modules/ROOT/images/advanced_configuration/diagnostics/diagnostics.png


+ 11 - 0
docs/modules/ROOT/images/advanced_configuration/diagnostics/screenshots.ini

@@ -0,0 +1,11 @@
+[DEFAULT]
+base_url = http://localhost:11337/
+dir = .
+width = 980
+height = 640
+post_script_sleep = 0.5
+
+[diagnostics]
+url = /diagnostics
+name = diagnostics
+script = setup_diagnostics.py

+ 54 - 0
docs/modules/ROOT/images/advanced_configuration/diagnostics/setup_diagnostics.py

@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+"""Open the diagnostics page from advanced_configuration/diagnostics.adoc."""
+
+import time
+
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+
+
+def _wait_for_diagnostics_page(driver, timeout=30):
+    WebDriverWait(driver, timeout).until(
+        lambda d: d.execute_script("return !!window.client")
+    )
+
+    def ready(d):
+        try:
+            ssh_heading = d.find_element(
+                By.XPATH,
+                '//*[self::h2 or self::h3][contains(normalize-space(), "SSH")]',
+            )
+            server_diagnostics_heading = d.find_element(
+                By.XPATH,
+                '//*[self::h2 or self::h3][contains(normalize-space(), "Server Diagnostics")]',
+            )
+            key_value = d.find_element(
+                By.XPATH,
+                '//dt[contains(normalize-space(), "Found Key")]/following-sibling::dd[1]',
+            )
+            config_value = d.find_element(
+                By.XPATH,
+                '//dt[contains(normalize-space(), "Found Config")]/following-sibling::dd[1]',
+            )
+        except Exception:
+            return False
+
+        return all(
+            element.is_displayed()
+            for element in (
+                ssh_heading,
+                server_diagnostics_heading,
+                key_value,
+                config_value,
+            )
+        ) and all(
+            element.text.strip() not in ("", "?")
+            for element in (key_value, config_value)
+        )
+
+    WebDriverWait(driver, timeout).until(ready)
+
+
+def run(driver):
+    _wait_for_diagnostics_page(driver)
+    time.sleep(0.2)

+ 2 - 0
docs/modules/ROOT/images/advanced_configuration/webui/hide-navigation/.gitignore

@@ -0,0 +1,2 @@
+custom-webui/
+__pycache__/

+ 2 - 0
docs/modules/ROOT/images/advanced_configuration/webui/hide-navigation/Makefile

@@ -0,0 +1,2 @@
+CONFIGDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+include ../../../screenshots.mk

+ 48 - 0
docs/modules/ROOT/images/advanced_configuration/webui/hide-navigation/config.yaml

@@ -0,0 +1,48 @@
+---
+listenAddressSingleHTTPFrontend: 0.0.0.0:11337
+
+logLevel: "WARN"
+checkForUpdates: false
+showFooter: false
+showNavigation: false
+
+actions:
+  - title: Ping the Internet
+    icon: ping
+    shell: ping -c 1 127.0.0.1
+  - title: Check disk space
+    icon: disk
+    shell: df -h
+  - title: check dmesg logs
+    icon: logs
+    shell: dmesg | tail -n 1
+  - title: date
+    icon: clock
+    shell: date
+  - title: Run backup script
+    icon: backup
+    shell: echo backup
+  - title: Ping host
+    icon: ping
+    shell: ping -c 1 127.0.0.1
+  - title: Restart Docker Container
+    icon: restart
+    shell: echo restart
+  - title: Delete old backups
+    icon: ashtonished
+    shell: echo delete
+  - title: Get OliveTin Theme
+    icon: theme
+    shell: echo theme
+  - title: Setup easy SSH
+    icon: ssh
+    shell: echo ssh
+  - title: Restart httpd on server1
+    icon: restart
+    shell: echo restart httpd
+  - title: Toggle GPIO light
+    icon: light
+    shell: echo toggle
+  - title: Run Automation Playbook
+    icon: robot
+    shell: echo ansible

BIN
docs/modules/ROOT/images/advanced_configuration/webui/hide-navigation/hide-navigation.png


+ 11 - 0
docs/modules/ROOT/images/advanced_configuration/webui/hide-navigation/screenshots.ini

@@ -0,0 +1,11 @@
+[DEFAULT]
+base_url = http://localhost:11337/
+dir = .
+width = 1180
+height = 760
+post_script_sleep = 0.5
+
+[hide-navigation]
+url = .
+name = hide-navigation
+script = setup_hide_navigation.py

+ 20 - 0
docs/modules/ROOT/images/advanced_configuration/webui/hide-navigation/setup_hide_navigation.py

@@ -0,0 +1,20 @@
+#!/usr/bin/env python3
+"""Capture the Actions view with navigation hidden."""
+
+import time
+
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+
+
+def run(driver):
+    WebDriverWait(driver, 15).until(
+        lambda d: bool(d.find_element(By.TAG_NAME, "body").get_attribute("loaded-dashboard"))
+    )
+    WebDriverWait(driver, 15).until(
+        lambda d: len(d.find_elements(By.ID, "mainnav")) == 0
+    )
+    WebDriverWait(driver, 15).until(
+        lambda d: len(d.find_elements(By.CSS_SELECTOR, ".action-button button")) >= 8
+    )
+    time.sleep(0.2)

+ 2 - 0
docs/modules/ROOT/images/advanced_configuration/webui/page-title/.gitignore

@@ -0,0 +1,2 @@
+custom-webui/
+__pycache__/

+ 2 - 0
docs/modules/ROOT/images/advanced_configuration/webui/page-title/Makefile

@@ -0,0 +1,2 @@
+CONFIGDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+include ../../../screenshots.mk

+ 19 - 0
docs/modules/ROOT/images/advanced_configuration/webui/page-title/config.yaml

@@ -0,0 +1,19 @@
+---
+listenAddressSingleHTTPFrontend: 0.0.0.0:11337
+
+logLevel: "WARN"
+checkForUpdates: false
+showFooter: false
+
+pageTitle: My OliveTin Instance
+
+actions:
+  - title: Ping the Internet
+    icon: ping
+    shell: ping -c 1 127.0.0.1
+  - title: Check disk space
+    icon: disk
+    shell: df -h /
+  - title: check dmesg logs
+    icon: logs
+    shell: dmesg | tail -n 1

BIN
docs/modules/ROOT/images/advanced_configuration/webui/page-title/page-title.png


+ 11 - 0
docs/modules/ROOT/images/advanced_configuration/webui/page-title/screenshots.ini

@@ -0,0 +1,11 @@
+[DEFAULT]
+base_url = http://localhost:11337/
+dir = .
+width = 980
+height = 220
+post_script_sleep = 0.5
+
+[page-title]
+url = .
+name = page-title
+script = setup_page_title.py

+ 20 - 0
docs/modules/ROOT/images/advanced_configuration/webui/page-title/setup_page_title.py

@@ -0,0 +1,20 @@
+#!/usr/bin/env python3
+"""Capture the custom page title from advanced_configuration/webui.adoc."""
+
+import time
+
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+
+
+def run(driver):
+    WebDriverWait(driver, 15).until(
+        lambda d: bool(d.find_element(By.TAG_NAME, "body").get_attribute("loaded-dashboard"))
+    )
+    WebDriverWait(driver, 15).until(
+        lambda d: "My OliveTin Instance" in d.find_element(By.CSS_SELECTOR, "header h1").text
+    )
+    WebDriverWait(driver, 15).until(
+        lambda d: d.find_element(By.CSS_SELECTOR, '[title="Ping the Internet"]').is_displayed()
+    )
+    time.sleep(0.2)

+ 2 - 0
docs/modules/ROOT/images/advanced_configuration/webui/sidebar/.gitignore

@@ -0,0 +1,2 @@
+custom-webui/
+__pycache__/

+ 2 - 0
docs/modules/ROOT/images/advanced_configuration/webui/sidebar/Makefile

@@ -0,0 +1,2 @@
+CONFIGDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+include ../../../screenshots.mk

+ 30 - 0
docs/modules/ROOT/images/advanced_configuration/webui/sidebar/config.yaml

@@ -0,0 +1,30 @@
+---
+listenAddressSingleHTTPFrontend: 0.0.0.0:11337
+
+logLevel: "WARN"
+checkForUpdates: false
+showFooter: false
+
+sectionNavigationStyle: sidebar
+
+actions:
+  - title: Check disk space
+    icon: disk
+    shell: df -h /
+  - title: Setup easy SSH
+    icon: ssh
+    shell: echo ssh
+  - title: My Servers ping
+    icon: ping
+    shell: echo ping
+  - title: My Containers list
+    icon: disk
+    shell: echo list
+
+dashboards:
+  - title: My Servers
+    contents:
+      - title: My Servers ping
+  - title: My Containers
+    contents:
+      - title: My Containers list

+ 11 - 0
docs/modules/ROOT/images/advanced_configuration/webui/sidebar/screenshots.ini

@@ -0,0 +1,11 @@
+[DEFAULT]
+base_url = http://localhost:11337/
+dir = .
+width = 980
+height = 520
+post_script_sleep = 0.5
+
+[sidebar]
+url = .
+name = sidebar
+script = setup_sidebar.py

+ 44 - 0
docs/modules/ROOT/images/advanced_configuration/webui/sidebar/setup_sidebar.py

@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+"""Capture the default sidebar navigation style."""
+
+import time
+
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+
+
+def _wait_for_sidebar_navigation(driver, timeout=30):
+    WebDriverWait(driver, timeout).until(
+        lambda d: bool(d.find_element(By.TAG_NAME, "body").get_attribute("loaded-dashboard"))
+    )
+
+    driver.find_element(By.ID, "sidebar-toggler-button").click()
+
+    WebDriverWait(driver, timeout).until(
+        lambda d: d.find_element(By.ID, "mainnav").is_displayed()
+    )
+
+    driver.find_element(By.CSS_SELECTOR, "#mainnav .stick-toggle").click()
+
+    def ready(d):
+        try:
+            my_servers = d.find_element(
+                By.XPATH,
+                '//*[@id="mainnav"]//a[contains(normalize-space(), "My Servers")]',
+            )
+            my_containers = d.find_element(
+                By.XPATH,
+                '//*[@id="mainnav"]//a[contains(normalize-space(), "My Containers")]',
+            )
+            disk_space = d.find_element(By.CSS_SELECTOR, '[title="Check disk space"]')
+            ssh = d.find_element(By.CSS_SELECTOR, '[title="Setup easy SSH"]')
+        except Exception:
+            return False
+        return all(element.is_displayed() for element in (my_servers, my_containers, disk_space, ssh))
+
+    WebDriverWait(driver, timeout).until(ready)
+
+
+def run(driver):
+    _wait_for_sidebar_navigation(driver)
+    time.sleep(0.2)

BIN
docs/modules/ROOT/images/advanced_configuration/webui/sidebar/sidebar.png


+ 2 - 0
docs/modules/ROOT/images/advanced_configuration/webui/topbar/.gitignore

@@ -0,0 +1,2 @@
+custom-webui/
+__pycache__/

+ 2 - 0
docs/modules/ROOT/images/advanced_configuration/webui/topbar/Makefile

@@ -0,0 +1,2 @@
+CONFIGDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+include ../../../screenshots.mk

+ 33 - 0
docs/modules/ROOT/images/advanced_configuration/webui/topbar/config.yaml

@@ -0,0 +1,33 @@
+---
+listenAddressSingleHTTPFrontend: 0.0.0.0:11337
+
+logLevel: "WARN"
+checkForUpdates: false
+showFooter: false
+
+sectionNavigationStyle: topbar
+
+actions:
+  - title: Ping host
+    icon: ping
+    shell: ping -c 1 127.0.0.1
+  - title: Restart Docker Container
+    icon: restart
+    shell: echo restart
+  - title: Delete old backups
+    icon: ashtonished
+    shell: echo delete
+  - title: Server ping
+    icon: ping
+    shell: echo ping
+  - title: Container list
+    icon: disk
+    shell: echo list
+
+dashboards:
+  - title: My Servers
+    contents:
+      - title: Server ping
+  - title: My Containers
+    contents:
+      - title: Container list

+ 11 - 0
docs/modules/ROOT/images/advanced_configuration/webui/topbar/screenshots.ini

@@ -0,0 +1,11 @@
+[DEFAULT]
+base_url = http://localhost:11337/
+dir = .
+width = 980
+height = 420
+post_script_sleep = 0.5
+
+[topbar]
+url = .
+name = topbar
+script = setup_topbar.py

+ 58 - 0
docs/modules/ROOT/images/advanced_configuration/webui/topbar/setup_topbar.py

@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+"""Capture the topbar section navigation style."""
+
+import time
+
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+
+
+def _wait_for_topbar_navigation(driver, timeout=30):
+    WebDriverWait(driver, timeout).until(
+        lambda d: bool(d.find_element(By.TAG_NAME, "body").get_attribute("loaded-dashboard"))
+    )
+
+    def ready(d):
+        try:
+            topbar = d.find_element(By.CSS_SELECTOR, "nav.topbar")
+            my_servers = d.find_element(
+                By.XPATH,
+                '//nav[contains(@class, "topbar")]//a[contains(normalize-space(), "My Servers")]',
+            )
+            my_containers = d.find_element(
+                By.XPATH,
+                '//nav[contains(@class, "topbar")]//a[contains(normalize-space(), "My Containers")]',
+            )
+            diagnostics = d.find_element(
+                By.XPATH,
+                '//nav[contains(@class, "topbar")]//a[contains(normalize-space(), "Diagnostics")]',
+            )
+            logs = d.find_element(
+                By.XPATH,
+                '//nav[contains(@class, "topbar")]//a[contains(normalize-space(), "Logs")]',
+            )
+            ping_host = d.find_element(By.CSS_SELECTOR, '[title="Ping host"]')
+            restart = d.find_element(By.CSS_SELECTOR, '[title="Restart Docker Container"]')
+            delete_backups = d.find_element(By.CSS_SELECTOR, '[title="Delete old backups"]')
+        except Exception:
+            return False
+
+        return topbar.is_displayed() and all(
+            element.is_displayed()
+            for element in (
+                my_servers,
+                my_containers,
+                diagnostics,
+                logs,
+                ping_host,
+                restart,
+                delete_backups,
+            )
+        )
+
+    WebDriverWait(driver, timeout).until(ready)
+
+
+def run(driver):
+    _wait_for_topbar_navigation(driver)
+    time.sleep(0.2)

BIN
docs/modules/ROOT/images/advanced_configuration/webui/topbar/topbar.png


+ 2 - 0
docs/modules/ROOT/images/advanced_configuration/webui/with-navigation/.gitignore

@@ -0,0 +1,2 @@
+custom-webui/
+__pycache__/

+ 2 - 0
docs/modules/ROOT/images/advanced_configuration/webui/with-navigation/Makefile

@@ -0,0 +1,2 @@
+CONFIGDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+include ../../../screenshots.mk

+ 47 - 0
docs/modules/ROOT/images/advanced_configuration/webui/with-navigation/config.yaml

@@ -0,0 +1,47 @@
+---
+listenAddressSingleHTTPFrontend: 0.0.0.0:11337
+
+logLevel: "WARN"
+checkForUpdates: false
+showFooter: false
+
+actions:
+  - title: Ping the Internet
+    icon: ping
+    shell: ping -c 1 127.0.0.1
+  - title: Check disk space
+    icon: disk
+    shell: df -h
+  - title: check dmesg logs
+    icon: logs
+    shell: dmesg | tail -n 1
+  - title: date
+    icon: clock
+    shell: date
+  - title: Run backup script
+    icon: backup
+    shell: echo backup
+  - title: Ping host
+    icon: ping
+    shell: ping -c 1 127.0.0.1
+  - title: Restart Docker Container
+    icon: restart
+    shell: echo restart
+  - title: Delete old backups
+    icon: ashtonished
+    shell: echo delete
+  - title: Get OliveTin Theme
+    icon: theme
+    shell: echo theme
+  - title: Setup easy SSH
+    icon: ssh
+    shell: echo ssh
+  - title: Restart httpd on server1
+    icon: restart
+    shell: echo restart httpd
+  - title: Toggle GPIO light
+    icon: light
+    shell: echo toggle
+  - title: Run Automation Playbook
+    icon: robot
+    shell: echo ansible

+ 11 - 0
docs/modules/ROOT/images/advanced_configuration/webui/with-navigation/screenshots.ini

@@ -0,0 +1,11 @@
+[DEFAULT]
+base_url = http://localhost:11337/
+dir = .
+width = 1180
+height = 760
+post_script_sleep = 0.5
+
+[with-navigation]
+url = .
+name = with-navigation
+script = setup_with_navigation.py

+ 23 - 0
docs/modules/ROOT/images/advanced_configuration/webui/with-navigation/setup_with_navigation.py

@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+"""Capture the default Actions view with sidebar navigation visible."""
+
+import time
+
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+
+
+def run(driver):
+    WebDriverWait(driver, 15).until(
+        lambda d: bool(d.find_element(By.TAG_NAME, "body").get_attribute("loaded-dashboard"))
+    )
+    WebDriverWait(driver, 15).until(
+        lambda d: len(d.find_elements(By.CSS_SELECTOR, ".action-button button")) >= 8
+    )
+
+    driver.find_element(By.ID, "sidebar-toggler-button").click()
+
+    WebDriverWait(driver, 15).until(
+        lambda d: d.find_element(By.ID, "mainnav").is_displayed()
+    )
+    time.sleep(0.2)

BIN
docs/modules/ROOT/images/advanced_configuration/webui/with-navigation/with-navigation.png


BIN
docs/modules/ROOT/images/args-multiline-text.png


+ 2 - 0
docs/modules/ROOT/images/args/confirmation/.gitignore

@@ -0,0 +1,2 @@
+custom-webui/
+__pycache__/

+ 2 - 0
docs/modules/ROOT/images/args/confirmation/Makefile

@@ -0,0 +1,2 @@
+CONFIGDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+include ../../screenshots.mk

+ 14 - 0
docs/modules/ROOT/images/args/confirmation/config.yaml

@@ -0,0 +1,14 @@
+---
+listenAddressSingleHTTPFrontend: 0.0.0.0:11337
+
+logLevel: "WARN"
+checkForUpdates: false
+showFooter: false
+
+actions:
+  - title: Delete old backups
+    icon: ashtonished
+    shell: echo "Deleted old backups"
+    arguments:
+      - type: confirmation
+        title: Are you sure?!

BIN
docs/modules/ROOT/images/args/confirmation/confirmation.png


+ 11 - 0
docs/modules/ROOT/images/args/confirmation/screenshots.ini

@@ -0,0 +1,11 @@
+[DEFAULT]
+base_url = http://localhost:11337/
+dir = .
+width = 800
+height = 420
+post_script_sleep = 0.5
+
+[confirmation]
+url = .
+name = confirmation
+script = setup_confirmation.py

+ 25 - 0
docs/modules/ROOT/images/args/confirmation/setup_confirmation.py

@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+"""Prepare the confirmation argument screenshot."""
+
+import time
+
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+
+
+def _wait_for_body_attr(driver, attr, timeout=15):
+    WebDriverWait(driver, timeout).until(
+        lambda d: bool(d.find_element(By.TAG_NAME, "body").get_attribute(attr))
+    )
+
+
+def run(driver):
+    _wait_for_body_attr(driver, "loaded-dashboard")
+
+    driver.find_element(By.CSS_SELECTOR, '[title="Delete old backups"]').click()
+    _wait_for_body_attr(driver, "loaded-argument-form")
+
+    WebDriverWait(driver, 15).until(
+        lambda d: not d.find_element(By.CSS_SELECTOR, 'button[name="start"]').is_enabled()
+    )
+    time.sleep(0.2)

BIN
docs/modules/ROOT/images/args/input/args1.png


BIN
docs/modules/ROOT/images/args/input/args2.png


BIN
docs/modules/ROOT/images/args/input/args3.png


+ 1 - 0
docs/modules/ROOT/images/args/input/screenshots.ini

@@ -19,3 +19,4 @@ script = setup_args2.py
 url = .
 name = args3
 script = setup_args3.py
+height = 560

+ 11 - 1
docs/modules/ROOT/images/args/input/setup_args3.py

@@ -65,5 +65,15 @@ def run(driver):
 
     _wait_for_logs_page(driver)
     _wait_for_execution_complete(driver)
-
+    WebDriverWait(driver, 15).until(
+        lambda d: "Hello World"
+        in d.execute_script(
+            """
+            if (!window.terminal || !window.terminal.getBufferAsString) {
+              return '';
+            }
+            return window.terminal.getBufferAsString();
+            """
+        )
+    )
     time.sleep(0.2)

+ 2 - 0
docs/modules/ROOT/images/args/textarea/.gitignore

@@ -0,0 +1,2 @@
+custom-webui/
+__pycache__/

+ 2 - 0
docs/modules/ROOT/images/args/textarea/Makefile

@@ -0,0 +1,2 @@
+CONFIGDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+include ../../screenshots.mk

+ 17 - 0
docs/modules/ROOT/images/args/textarea/config.yaml

@@ -0,0 +1,17 @@
+---
+listenAddressSingleHTTPFrontend: 0.0.0.0:11337
+
+logLevel: "WARN"
+checkForUpdates: false
+showFooter: false
+
+actions:
+  - title: Save text to file
+    shell: 'echo "{{ content }}" > file'
+    arguments:
+      - type: raw_string_multiline
+        name: content
+        title: Content
+        default: |
+          Line one of the message
+          Line two of the message

BIN
docs/modules/ROOT/images/args/textarea/multiline-text.png


+ 11 - 0
docs/modules/ROOT/images/args/textarea/screenshots.ini

@@ -0,0 +1,11 @@
+[DEFAULT]
+base_url = http://localhost:11337/
+dir = .
+width = 800
+height = 520
+post_script_sleep = 0.5
+
+[multiline-text]
+url = .
+name = multiline-text
+script = setup_textarea.py

+ 27 - 0
docs/modules/ROOT/images/args/textarea/setup_textarea.py

@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+"""Prepare the multiline textarea argument screenshot."""
+
+import time
+
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+
+
+def _wait_for_body_attr(driver, attr, timeout=15):
+    WebDriverWait(driver, timeout).until(
+        lambda d: bool(d.find_element(By.TAG_NAME, "body").get_attribute(attr))
+    )
+
+
+def run(driver):
+    _wait_for_body_attr(driver, "loaded-dashboard")
+
+    driver.find_element(By.CSS_SELECTOR, '[title="Save text to file"]').click()
+
+    WebDriverWait(driver, 15).until(
+        lambda d: len(
+            d.find_elements(By.CSS_SELECTOR, "#argument-popup textarea#content")
+        )
+        >= 1
+    )
+    time.sleep(0.2)

+ 2 - 0
docs/modules/ROOT/images/dashboards/fieldsets/.gitignore

@@ -0,0 +1,2 @@
+custom-webui/
+__pycache__/

+ 2 - 0
docs/modules/ROOT/images/dashboards/fieldsets/Makefile

@@ -0,0 +1,2 @@
+CONFIGDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+include ../../screenshots.mk

+ 25 - 0
docs/modules/ROOT/images/dashboards/fieldsets/config.yaml

@@ -0,0 +1,25 @@
+---
+listenAddressSingleHTTPFrontend: 0.0.0.0:11337
+
+logLevel: "WARN"
+checkForUpdates: false
+showFooter: false
+
+actions:
+  - title: Placeholder 1
+    shell: echo "placeholder 1"
+  - title: Placeholder 2
+    shell: echo "placeholder 2"
+
+dashboards:
+  - title: My First Dashboard
+    contents:
+      - title: Fieldset 1
+        type: fieldset
+        contents:
+          - title: Folder 1
+            contents:
+              - title: Placeholder 1
+          - title: Folder 2
+            contents:
+              - title: Placeholder 2

BIN
docs/modules/ROOT/images/dashboards/fieldsets/fieldset.png


+ 11 - 0
docs/modules/ROOT/images/dashboards/fieldsets/screenshots.ini

@@ -0,0 +1,11 @@
+[DEFAULT]
+base_url = http://localhost:11337/
+dir = .
+width = 980
+height = 400
+post_script_sleep = 0.5
+
+[fieldset]
+url = /dashboards/My%%20First%%20Dashboard
+name = fieldset
+script = setup_fieldset.py

+ 35 - 0
docs/modules/ROOT/images/dashboards/fieldsets/setup_fieldset.py

@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+"""Open My First Dashboard from dashboards/2-fieldsets.adoc."""
+
+import time
+
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+
+
+def _wait_for_fieldset_dashboard(driver, timeout=30):
+    WebDriverWait(driver, timeout).until(
+        lambda d: d.find_element(By.TAG_NAME, "body").get_attribute("loaded-dashboard")
+        == "My First Dashboard"
+    )
+
+    def ready(d):
+        try:
+            folder1 = d.find_element(
+                By.XPATH,
+                '//button[contains(@class, "directory-button")]//span[contains(@class, "title") and text()="Folder 1"]',
+            )
+            folder2 = d.find_element(
+                By.XPATH,
+                '//button[contains(@class, "directory-button")]//span[contains(@class, "title") and text()="Folder 2"]',
+            )
+        except Exception:
+            return False
+        return all(element.is_displayed() for element in (folder1, folder2))
+
+    WebDriverWait(driver, timeout).until(ready)
+
+
+def run(driver):
+    _wait_for_fieldset_dashboard(driver)
+    time.sleep(0.2)

+ 2 - 0
docs/modules/ROOT/images/dashboards/folders/.gitignore

@@ -0,0 +1,2 @@
+custom-webui/
+__pycache__/

+ 2 - 0
docs/modules/ROOT/images/dashboards/folders/Makefile

@@ -0,0 +1,2 @@
+CONFIGDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+include ../../screenshots.mk

+ 33 - 0
docs/modules/ROOT/images/dashboards/folders/config.yaml

@@ -0,0 +1,33 @@
+---
+listenAddressSingleHTTPFrontend: 0.0.0.0:11337
+
+logLevel: "WARN"
+checkForUpdates: false
+showFooter: false
+
+actions:
+  - title: Action 1
+    shell: echo "action1"
+  - title: Action 2
+    shell: echo "action2"
+  - title: Action 3
+    shell: echo "action3"
+  - title: Action 4
+    shell: echo "action4"
+
+dashboards:
+  - title: My First Dashboard
+    contents:
+      - title: Fieldset 1
+        type: fieldset
+        contents:
+          - title: Folder 1
+            contents:
+              - title: Action 1
+              - title: Action 2
+              - title: Subfolder 2
+                contents:
+                  - title: Action 3
+          - title: Folder 2
+            contents:
+              - title: Action 4

BIN
docs/modules/ROOT/images/dashboards/folders/folders.png


+ 11 - 0
docs/modules/ROOT/images/dashboards/folders/screenshots.ini

@@ -0,0 +1,11 @@
+[DEFAULT]
+base_url = http://localhost:11337/
+dir = .
+width = 980
+height = 640
+post_script_sleep = 0.5
+
+[folders]
+url = /dashboards/Folder%%201
+name = folders
+script = setup_folders.py

+ 36 - 0
docs/modules/ROOT/images/dashboards/folders/setup_folders.py

@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+"""Open Folder 1 from dashboards/3-folders.adoc."""
+
+import time
+
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+
+
+def _wait_for_folder_dashboard(driver, timeout=30):
+    WebDriverWait(driver, timeout).until(
+        lambda d: d.find_element(By.TAG_NAME, "body").get_attribute("loaded-dashboard")
+        == "Folder 1"
+    )
+
+    def ready(d):
+        try:
+            action1 = d.find_element(By.CSS_SELECTOR, '[title="Action 1"]')
+            action2 = d.find_element(By.CSS_SELECTOR, '[title="Action 2"]')
+            subfolder = d.find_element(
+                By.XPATH,
+                '//button[contains(@class, "directory-button")]//span[contains(@class, "title") and text()="Subfolder 2"]',
+            )
+        except Exception:
+            return False
+        return all(
+            element.is_displayed()
+            for element in (action1, action2, subfolder)
+        )
+
+    WebDriverWait(driver, timeout).until(ready)
+
+
+def run(driver):
+    _wait_for_folder_dashboard(driver)
+    time.sleep(0.2)

BIN
docs/modules/ROOT/images/dashboards/intro/preview.png


+ 1 - 1
docs/modules/ROOT/images/dashboards/intro/screenshots.ini

@@ -6,6 +6,6 @@ height = 720
 post_script_sleep = 0.5
 
 [preview]
-url = /dashboards/My%20Servers
+url = /dashboards/My%%20Servers
 name = preview
 script = setup_preview.py

BIN
docs/modules/ROOT/images/defaultUiHideNav.png


BIN
docs/modules/ROOT/images/defaultUiWithNav.png


BIN
docs/modules/ROOT/images/diagnostics.png


BIN
docs/modules/ROOT/images/fieldset.png


BIN
docs/modules/ROOT/images/folders.png


BIN
docs/modules/ROOT/images/gitops.png


+ 0 - 0
docs/modules/ROOT/images/hacs-custom-repo.png → docs/modules/ROOT/images/integrations/hass/hacs-custom-repo.png


+ 0 - 0
docs/modules/ROOT/images/hacs-download.png → docs/modules/ROOT/images/integrations/hass/hacs-download.png


+ 0 - 0
docs/modules/ROOT/images/hacs-dropdown.png → docs/modules/ROOT/images/integrations/hass/hacs-dropdown.png


+ 0 - 0
docs/modules/ROOT/images/hacs-search.png → docs/modules/ROOT/images/integrations/hass/hacs-search.png


+ 0 - 0
docs/modules/ROOT/images/hass-add-integration.png → docs/modules/ROOT/images/integrations/hass/hass-add-integration.png


+ 0 - 0
docs/modules/ROOT/images/hass-buttons.png → docs/modules/ROOT/images/integrations/hass/hass-buttons.png


+ 0 - 0
docs/modules/ROOT/images/hass-configure-integration.png → docs/modules/ROOT/images/integrations/hass/hass-configure-integration.png


+ 0 - 0
docs/modules/ROOT/images/hass-devices-and-services.png → docs/modules/ROOT/images/integrations/hass/hass-devices-and-services.png


+ 0 - 0
docs/modules/ROOT/images/hassButtonSetup.png → docs/modules/ROOT/images/integrations/hass/hassButtonSetup.png


+ 0 - 0
docs/modules/ROOT/images/hassConfigYaml.png → docs/modules/ROOT/images/integrations/hass/hassConfigYaml.png


+ 0 - 0
docs/modules/ROOT/images/hassFileEditor.png → docs/modules/ROOT/images/integrations/hass/hassFileEditor.png


Некоторые файлы не были показаны из-за большого количества измененных файлов