diff --git a/app/Models/Plugin.php b/app/Models/Plugin.php index c791333..524f26a 100644 --- a/app/Models/Plugin.php +++ b/app/Models/Plugin.php @@ -153,105 +153,67 @@ class Plugin extends Model public function updateDataPayload(): void { - if ($this->data_strategy === 'polling' && $this->polling_url) { - - $headers = ['User-Agent' => 'usetrmnl/byos_laravel', 'Accept' => 'application/json']; - - if ($this->polling_header) { - // Resolve Liquid variables in the polling header - $resolvedHeader = $this->resolveLiquidVariables($this->polling_header); - $headerLines = explode("\n", mb_trim($resolvedHeader)); - foreach ($headerLines as $line) { - $parts = explode(':', $line, 2); - if (count($parts) === 2) { - $headers[mb_trim($parts[0])] = mb_trim($parts[1]); - } - } - } - - // Resolve Liquid variables in the entire polling_url field first, then split by newline - $resolvedPollingUrls = $this->resolveLiquidVariables($this->polling_url); - $urls = array_filter( - array_map('trim', explode("\n", $resolvedPollingUrls)), - fn ($url): bool => ! empty($url) - ); - - // If only one URL, use the original logic without nesting - if (count($urls) === 1) { - $url = reset($urls); - $httpRequest = Http::withHeaders($headers); - - if ($this->polling_verb === 'post' && $this->polling_body) { - // Resolve Liquid variables in the polling body - $resolvedBody = $this->resolveLiquidVariables($this->polling_body); - $httpRequest = $httpRequest->withBody($resolvedBody); - } - - // URL is already resolved, use it directly - $resolvedUrl = $url; - - try { - // Make the request based on the verb - $httpResponse = $this->polling_verb === 'post' ? $httpRequest->post($resolvedUrl) : $httpRequest->get($resolvedUrl); - - $response = $this->parseResponse($httpResponse); - - $this->update([ - 'data_payload' => $response, - 'data_payload_updated_at' => now(), - ]); - } catch (Exception $e) { - Log::warning("Failed to fetch data from URL {$resolvedUrl}: ".$e->getMessage()); - $this->update([ - 'data_payload' => ['error' => 'Failed to fetch data'], - 'data_payload_updated_at' => now(), - ]); - } - - return; - } - - // Multiple URLs - use nested response logic - $combinedResponse = []; - - foreach ($urls as $index => $url) { - $httpRequest = Http::withHeaders($headers); - - if ($this->polling_verb === 'post' && $this->polling_body) { - // Resolve Liquid variables in the polling body - $resolvedBody = $this->resolveLiquidVariables($this->polling_body); - $httpRequest = $httpRequest->withBody($resolvedBody); - } - - // URL is already resolved, use it directly - $resolvedUrl = $url; - - try { - // Make the request based on the verb - $httpResponse = $this->polling_verb === 'post' ? $httpRequest->post($resolvedUrl) : $httpRequest->get($resolvedUrl); - - $response = $this->parseResponse($httpResponse); - - // Check if response is an array at root level - if (array_keys($response) === range(0, count($response) - 1)) { - // Response is a sequential array, nest under .data - $combinedResponse["IDX_{$index}"] = ['data' => $response]; - } else { - // Response is an object or associative array, keep as is - $combinedResponse["IDX_{$index}"] = $response; - } - } catch (Exception $e) { - // Log error and continue with other URLs - Log::warning("Failed to fetch data from URL {$resolvedUrl}: ".$e->getMessage()); - $combinedResponse["IDX_{$index}"] = ['error' => 'Failed to fetch data']; - } - } - - $this->update([ - 'data_payload' => $combinedResponse, - 'data_payload_updated_at' => now(), - ]); + if ($this->data_strategy !== 'polling' || !$this->polling_url) { + return; } + $headers = ['User-Agent' => 'usetrmnl/byos_laravel', 'Accept' => 'application/json']; + + // resolve headers + if ($this->polling_header) { + $resolvedHeader = $this->resolveLiquidVariables($this->polling_header); + $headerLines = explode("\n", mb_trim($resolvedHeader)); + foreach ($headerLines as $line) { + $parts = explode(':', $line, 2); + if (count($parts) === 2) { + $headers[mb_trim($parts[0])] = mb_trim($parts[1]); + } + } + } + + // resolve and clean URLs + $resolvedPollingUrls = $this->resolveLiquidVariables($this->polling_url); + $urls = array_values(array_filter( // array_values ensures 0, 1, 2... + array_map('trim', explode("\n", $resolvedPollingUrls)), + fn ($url): bool => filled($url) + )); + + $combinedResponse = []; + + // Loop through all URLs (Handles 1 or many) + foreach ($urls as $index => $url) { + $httpRequest = Http::withHeaders($headers); + + if ($this->polling_verb === 'post' && $this->polling_body) { + $resolvedBody = $this->resolveLiquidVariables($this->polling_body); + $httpRequest = $httpRequest->withBody($resolvedBody); + } + + try { + $httpResponse = ($this->polling_verb === 'post') + ? $httpRequest->post($url) + : $httpRequest->get($url); + + $response = $this->parseResponse($httpResponse); + + // Nest if it's a sequential array + if (array_keys($response) === range(0, count($response) - 1)) { + $combinedResponse["IDX_{$index}"] = ['data' => $response]; + } else { + $combinedResponse["IDX_{$index}"] = $response; + } + } catch (Exception $e) { + Log::warning("Failed to fetch data from URL {$url}: ".$e->getMessage()); + $combinedResponse["IDX_{$index}"] = ['error' => 'Failed to fetch data']; + } + } + + // unwrap IDX_0 if only one URL + $finalPayload = (count($urls) === 1) ? reset($combinedResponse) : $combinedResponse; + + $this->update([ + 'data_payload' => $finalPayload, + 'data_payload_updated_at' => now(), + ]); } private function parseResponse(Response $httpResponse): array diff --git a/resources/css/app.css b/resources/css/app.css index 30cb7a1..de95b81 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -72,3 +72,39 @@ select:focus[data-flux-control] { /* \[:where(&)\]:size-4 { @apply size-4; } */ + +@layer components { + /* standard container for app */ + .styled-container, + .tab-button { + @apply rounded-xl border bg-white dark:bg-stone-950 dark:border-zinc-700 text-stone-800 shadow-xs; + } + + .tab-button { + @apply flex items-center gap-2 px-4 py-2 text-sm font-medium; + @apply rounded-b-none shadow-none bg-inherit; + + /* This makes the button sit slightly over the box border */ + margin-bottom: -1px; + position: relative; + z-index: 1; + } + + .tab-button.is-active { + @apply text-zinc-700 dark:text-zinc-300; + @apply border-b-white dark:border-b-zinc-800; + + /* Z-index 10 ensures the bottom border of the tab hides the top border of the box */ + z-index: 10; + } + + .tab-button:not(.is-active) { + @apply text-zinc-500 border-transparent; + } + + .tab-button:not(.is-active):hover { + @apply text-zinc-700 dark:text-zinc-300; + @apply border-zinc-300 dark:border-zinc-700; + cursor: pointer; + } +} diff --git a/resources/views/components/layouts/auth/card.blade.php b/resources/views/components/layouts/auth/card.blade.php index 1a316ef..b5a62c6 100644 --- a/resources/views/components/layouts/auth/card.blade.php +++ b/resources/views/components/layouts/auth/card.blade.php @@ -15,7 +15,7 @@
Add playlists to your devices to see them here.
diff --git a/resources/views/livewire/plugins/index.blade.php b/resources/views/livewire/plugins/index.blade.php index 4347aaf..d902183 100644 --- a/resources/views/livewire/plugins/index.blade.php +++ b/resources/views/livewire/plugins/index.blade.php @@ -395,7 +395,7 @@ new class extends Component { wire:key="plugin-{{ $plugin['id'] ?? $plugin['name'] ?? $index }}" x-data="{ pluginName: {{ json_encode(strtolower($plugin['name'] ?? '')) }} }" x-show="searchTerm.length <= 1 || pluginName.includes(searchTerm.toLowerCase())" - class="rounded-xl border bg-white dark:bg-stone-950 dark:border-stone-800 text-stone-800 shadow-xs"> + class="styled-container">