diff --git a/Shoko/shoko.svg b/Shoko/shoko.svg index f63e0b22c4..87ac7aa229 100644 --- a/Shoko/shoko.svg +++ b/Shoko/shoko.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/Steerhouse/Steerhouse.php b/Steerhouse/Steerhouse.php new file mode 100644 index 0000000000..6356dda4f3 --- /dev/null +++ b/Steerhouse/Steerhouse.php @@ -0,0 +1,68 @@ +url('api/stats'), $this->getAttrs()); + echo $test->status; + } + + public function livestats() + { + $status = 'inactive'; + $data = [ + 'running' => 0, + 'queued' => 0, + 'failed' => 0, + ]; + + // GET /api/stats returns counts only, e.g. {"queued": 0, "running": 2, "succeeded_24h": 14, + // "failed_24h": 1, "workers_online": 3}. execute() returns null when the connection fails; + // a bad key gets a 401 whose body has no counts, so the tile stays at zero and inactive. + $res = parent::execute($this->url('api/stats'), $this->getAttrs()); + if ($res !== null && $res->getStatusCode() === 200) { + $body = json_decode($res->getBody()); + if (isset($body->running, $body->queued, $body->failed_24h)) { + $data['running'] = (int) $body->running; + $data['queued'] = (int) $body->queued; + $data['failed'] = (int) $body->failed_24h; + // Refresh every 5 seconds while runs are waiting or in progress, else every 30. + if ($data['running'] > 0 || $data['queued'] > 0) { + $status = 'active'; + } + } + } + + return parent::getLiveStats($status, $data); + } + + private function getAttrs() + { + // A "stats" API key from Projects -> API keys in Steerhouse: it can read these counts only. + $attrs = [ + 'headers' => [ + 'Accept' => 'application/json', + 'Authorization' => 'Bearer ' . ($this->config->apikey ?? ''), + ], + ]; + if (!empty($this->config->ignore_tls)) { + $attrs['verify'] = false; + } + return $attrs; + } + + public function url($endpoint) + { + $api_url = parent::normaliseurl($this->config->url) . $endpoint; + return $api_url; + } +} diff --git a/Steerhouse/app.json b/Steerhouse/app.json new file mode 100644 index 0000000000..eb5003ab91 --- /dev/null +++ b/Steerhouse/app.json @@ -0,0 +1,10 @@ +{ + "appid": "422c6bf3a19cca6e7c2e59a393b1838cca9bb6e9", + "name": "Steerhouse", + "website": "https://github.com/HoneyBearTech/Steerhouse", + "license": "MIT License", + "description": "Self-hosted web UI and API for running Ansible playbooks, with per-project access control, isolated workers and a full audit trail.", + "enhanced": true, + "tile_background": "dark", + "icon": "steerhouse.svg" +} diff --git a/Steerhouse/config.blade.php b/Steerhouse/config.blade.php new file mode 100644 index 0000000000..51a673a866 --- /dev/null +++ b/Steerhouse/config.blade.php @@ -0,0 +1,31 @@ +

{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')

+
+
+ + {!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!} +
+
+ + {!! Form::input('password', 'config[apikey]', isset($item) ? ($item->getconfig()->apikey ?? null) : null, ['placeholder' => __('app.apps.apikey'), 'data-config' => 'apikey', 'class' => 'form-control config-item']) !!} +
+
+ +
+ {!! Form::hidden('config[ignore_tls]', 0, ['class' => 'config-item', 'data-config' => 'ignore_tls']) !!} + +
+
+
+ +
+
diff --git a/Steerhouse/livestats.blade.php b/Steerhouse/livestats.blade.php new file mode 100644 index 0000000000..bb81f043fb --- /dev/null +++ b/Steerhouse/livestats.blade.php @@ -0,0 +1,14 @@ + diff --git a/Steerhouse/steerhouse.svg b/Steerhouse/steerhouse.svg new file mode 100644 index 0000000000..bc0cc5d3bd --- /dev/null +++ b/Steerhouse/steerhouse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Verdaccio/verdaccio.svg b/Verdaccio/verdaccio.svg index 8a98484a4a..37b7017f1e 100644 --- a/Verdaccio/verdaccio.svg +++ b/Verdaccio/verdaccio.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file