Compare commits

...

8 Commits

19 changed files with 261 additions and 289 deletions

View File

@@ -1,4 +1,4 @@
FROM dunglas/frankenphp
FROM dunglas/frankenphp:php8.4-alpine
ENV SERVER_NAME=":80"
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
@@ -11,6 +11,8 @@ RUN install-php-extensions \
zip \
opcache
RUN apk add --no-cache wget
HEALTHCHECK --interval=3s --timeout=3s --retries=10 CMD [ "php", "/app/bin/console", "startup:status" ]
COPY docker/app/Caddyfile /etc/frankenphp/Caddyfile

View File

@@ -7,7 +7,13 @@ import { getComponent } from '@symfony/ux-live-component';
/* stimulusFetch: 'lazy' */
export default class extends Controller {
static targets = ['download']
static targets = ['download', 'downloadRow', 'viewAllBtn']
static values = {
isWidget: Boolean,
perPage: Number,
}
component = null;
async initialize() {
this.component = await getComponent(this.element);
@@ -22,9 +28,38 @@ export default class extends Controller {
// this.fooTarget.addEventListener('click', this._fooBar)
}
downloadRowTargetConnected(target) {
if (Boolean(target.getAttribute('isBroadcasted')) === true) {
this.viewAllBtnTarget.parentElement.append(this.viewAllBtnTarget);
if (this.downloadRowTargets.length > this.perPageValue) {
target.classList.add('hidden');
this.viewAllBtnTarget.classList.remove('hidden');
} else {
this.viewAllBtnTarget.classList.add('hidden');
}
}
}
downloadRowTargetDisconnected(target) {
this.viewAllBtnTarget.parentElement.append(this.viewAllBtnTarget);
let i = 1;
this.downloadRowTargets.forEach((downloadRow) => {
console.log(downloadRow)
if (i <= this.perPageValue) {
downloadRow.classList.remove('hidden');
} else {
downloadRow.classList.add('hidden');
}
})
if (this.downloadRowTargets.length > this.perPage) {
this.viewAllBtnTarget.classList.remove('hidden');
}
}
downloadTargetConnected(target) {
let downloads = this.element.querySelectorAll('tbody tr');
if (downloads.length > 5) {
if (downloads.length > this.perPageValue) {
target.classList.add('hidden');
}
}

View File

@@ -35,7 +35,7 @@ services:
volumes:
- $PWD:/app
tty: true
command: php /app/bin/console messenger:consume async -vv --time-limit=3600 limit=10
command: php /app/bin/console messenger:consume async -vv --time-limit=3600 --limit=10
scheduler:

View File

@@ -11,6 +11,8 @@ RUN install-php-extensions \
zip \
opcache
RUN apk add --no-cache wget
COPY . /app
ENTRYPOINT [ "php", "/app/bin/console", "messenger:consume", "async" ]

View File

@@ -2,34 +2,25 @@
namespace App\Controller;
use App\Util\Broadcaster;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Symfony\Component\Routing\Attribute\Route;
use Twig\Environment;
final class AlertController extends AbstractController
{
public function __construct(
#[Autowire(service: 'twig')] private readonly Environment $renderer,
private readonly HubInterface $hub,
private readonly Broadcaster $broadcaster,
) {}
#[Route('/alert', name: 'app_alert')]
public function index(): Response
{
$update = new Update(
'alerts',
$this->renderer->render('Alert.stream.html.twig', [
'alert_id' => 1,
'title' => 'Added to queue',
'message' => 'This is a testy test!',
])
$this->broadcaster->alert(
'Added to queue',
'This is a testy test!'
);
$this->hub->publish($update);
return $this->json([
'Success' => 'Published'
]);

View File

@@ -6,12 +6,11 @@ use App\Torrentio\Action\Handler\GetMovieOptionsHandler;
use App\Torrentio\Action\Handler\GetTvShowOptionsHandler;
use App\Torrentio\Action\Input\GetMovieOptionsInput;
use App\Torrentio\Action\Input\GetTvShowOptionsInput;
use App\Util\Broadcaster;
use Carbon\Carbon;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
@@ -21,8 +20,7 @@ final class TorrentioController extends AbstractController
public function __construct(
private readonly GetMovieOptionsHandler $getMovieOptionsHandler,
private readonly GetTvShowOptionsHandler $getTvShowOptionsHandler,
private readonly HubInterface $hub,
private readonly \Twig\Environment $renderer,
private readonly Broadcaster $broadcaster,
) {}
#[Route('/torrentio/movies/{tmdbId}/{imdbId}', name: 'app_torrentio_movies')]
@@ -75,14 +73,10 @@ final class TorrentioController extends AbstractController
);
$cache->delete($cacheId);
$this->hub->publish(new Update(
$request->getSession()->get('mercure_alert_topic'),
$this->renderer->render('Alert.stream.html.twig', [
'alert_id' => uniqid(),
'title' => 'Success',
'message' => 'Torrentio cache Cleared.',
])
));
$this->broadcaster->alert(
title: 'Success',
message: 'Torrentio cache Cleared.'
);
return $cache->get($cacheId, function (ItemInterface $item) use ($input) {
$item->expiresAt(Carbon::now()->addHour()->setMinute(0)->setSecond(0));

View File

@@ -6,11 +6,9 @@ use App\Download\Action\Handler\DeleteDownloadHandler;
use App\Download\Action\Input\DeleteDownloadInput;
use App\Download\Action\Input\DownloadMediaInput;
use App\Download\Framework\Repository\DownloadRepository;
use App\Util\Broadcaster;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Attribute\Route;
@@ -19,12 +17,11 @@ class ApiController extends AbstractController
public function __construct(
private DownloadRepository $downloadRepository,
private MessageBusInterface $bus,
private readonly HubInterface $hub,
private readonly Broadcaster $broadcaster,
) {}
#[Route('/api/download', name: 'api_download', methods: ['POST'])]
public function download(
Request $request,
DownloadMediaInput $input,
): Response {
$download = $this->downloadRepository->insert(
@@ -47,33 +44,24 @@ class ApiController extends AbstractController
return $this->json(['error' => $exception->getMessage()], Response::HTTP_INTERNAL_SERVER_ERROR);
}
$this->hub->publish(new Update(
$request->getSession()->get('mercure_alert_topic'),
$this->renderView('broadcast/Alert.stream.html.twig', [
'alert_id' => uniqid(),
'title' => 'Success',
'message' => '"' . $input->title . '" added to Queue',
])
));
$this->broadcaster->alert(
title: 'Success',
message: "$input->title added to Queue."
);
return $this->json(['status' => 200, 'message' => 'Added to Queue']);
}
#[Route('/api/download/{downloadId}', name: 'api_download_delete', methods: ['DELETE'])]
public function deleteDownload(
Request $request,
DeleteDownloadInput $input,
DeleteDownloadHandler $handler,
): Response {
$result = $handler->handle($input->toCommand());
$this->hub->publish(new Update(
$request->getSession()->get('mercure_alert_topic'),
$this->renderView('broadcast/Alert.stream.html.twig', [
'alert_id' => uniqid(),
'title' => 'Success',
'message' => '"' . $result->download->getTitle() . '" has been deleted.',
])
));
$this->broadcaster->alert(
title: 'Success',
message: "{$result->download->getTitle()} has been deleted.",
);
return $this->json(['status' => 200, 'message' => 'Download Deleted']);
}

View File

@@ -7,19 +7,18 @@ use App\Monitor\Action\Handler\AddMonitorHandler;
use App\Monitor\Action\Handler\DeleteMonitorHandler;
use App\Monitor\Action\Input\AddMonitorInput;
use App\Monitor\Action\Input\DeleteMonitorInput;
use App\Util\Broadcaster;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Symfony\Component\Routing\Attribute\Route;
use Twig\Environment;
class ApiController extends AbstractController
{
public function __construct(
#[Autowire(service: 'twig')]
private readonly Environment $renderer,
private readonly Broadcaster $broadcaster,
) {}
#[Route('/api/monitor', name: 'api_monitor', methods: ['POST'])]
@@ -32,14 +31,10 @@ class ApiController extends AbstractController
$command->userId = $this->getUser()->getId();
$response = $handler->handle($command);
$hub->publish(new Update(
'alerts',
$this->renderer->render('broadcast/Alert.stream.html.twig', [
'alert_id' => uniqid(),
'title' => 'Success',
'message' => "New monitor added for {$input->title}",
])
));
$this->broadcaster->alert(
title: 'Success',
message: "New monitor added for {$input->title}",
);
return $this->json([
'status' => 200,

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Twig\Components;
use App\Download\Framework\Entity\Download;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent]
final class DownloadListRow
{
public Download $download;
public bool $isWidget = true;
public bool $isBroadcasted = false;
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Twig\Components;
use App\Monitor\Framework\Entity\Monitor;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent]
final class MonitorListRow
{
public Monitor $monitor;
}

View File

@@ -9,23 +9,20 @@ use App\User\Action\Handler\SaveUserMediaPreferencesHandler;
use App\User\Action\Input\SaveUserDownloadPreferencesInput;
use App\User\Action\Input\SaveUserMediaPreferencesInput;
use App\User\Framework\Repository\PreferencesRepository;
use App\Util\Broadcaster;
use App\Util\CountryLanguages;
use App\Util\ProviderList;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Symfony\Component\Routing\Attribute\Route;
class PreferencesController extends AbstractController
{
public function __construct(
private readonly PreferencesRepository $preferencesRepository,
private readonly SaveUserMediaPreferencesHandler $saveUserMediaPreferencesHandler,
private readonly HubInterface $hub,
private readonly SaveUserDownloadPreferencesHandler $saveUserDownloadPreferencesHandler,
private readonly Broadcaster $broadcaster,
) {}
#[Route('/user/preferences', 'app_user_preferences', methods: ['GET'])]
public function mediaPreferences(): Response
{
@@ -48,25 +45,21 @@ class PreferencesController extends AbstractController
#[Route('/user/preferences/media', 'app_save_media_preferences', methods: ['POST'])]
public function saveMediaPreferences(
Request $request,
SaveUserMediaPreferencesInput $input,
SaveUserMediaPreferencesHandler $saveUserMediaPreferencesHandler,
): Response
{
$this->saveUserMediaPreferencesHandler->handle($input->toCommand());
$saveUserMediaPreferencesHandler->handle($input->toCommand());
$mediaPreferences = $this->getUser()->getMediaPreferences();
$downloadPreferences = $this->getUser()->getDownloadPreferences();
$languages = CountryLanguages::$languages;
sort($languages);
$this->hub->publish(new Update(
$request->getSession()->get('mercure_alert_topic'),
$this->renderView('broadcast/Alert.stream.html.twig', [
'alert_id' => uniqid(),
'title' => 'Success',
'message' => 'Your media preferences have been saved.',
])
));
$this->broadcaster->alert(
title: 'Success',
message: 'Your media preferences have been saved.'
);
return $this->render(
'user/preferences.html.twig',
@@ -82,24 +75,20 @@ class PreferencesController extends AbstractController
#[Route('/user/preferences/download', 'app_save_download_preferences', methods: ['POST'])]
public function saveDownloadPreferences(
Request $request,
SaveUserDownloadPreferencesInput $input,
SaveUserDownloadPreferencesHandler $saveUserDownloadPreferencesHandler,
): Response
{
$downloadPreferences = $this->saveUserDownloadPreferencesHandler->handle($input->toCommand())->downloadPreferences;
$downloadPreferences = $saveUserDownloadPreferencesHandler->handle($input->toCommand())->downloadPreferences;
$mediaPreferences = $this->getUser()->getMediaPreferences();
$languages = CountryLanguages::$languages;
sort($languages);
$this->hub->publish(new Update(
$request->getSession()->get('mercure_alert_topic'),
$this->renderView('broadcast/Alert.stream.html.twig', [
'alert_id' => uniqid(),
'title' => 'Success',
'message' => 'Your download preferences have been saved.',
])
));
$this->broadcaster->alert(
title: 'Success',
message: 'Your download preferences have been saved.'
);
return $this->render(
'user/preferences.html.twig',

33
src/Util/Broadcaster.php Normal file
View File

@@ -0,0 +1,33 @@
<?php
namespace App\Util;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Twig\Environment;
readonly class Broadcaster
{
public function __construct(
#[Autowire(service: 'twig')]
private Environment $renderer,
private HubInterface $hub,
private RequestStack $requestStack,
) {}
public function alert(string $title, string $message): void
{
$userAlertTopic = $this->requestStack->getCurrentRequest()->getSession()->get('mercure_alert_topic');
$update = new Update(
$userAlertTopic,
$this->renderer->render('broadcast/Alert.stream.html.twig', [
'alert_id' => uniqid(),
'title' => $title,
'message' => $message,
])
);
$this->hub->publish($update);
}
}

View File

@@ -7,7 +7,7 @@ module.exports = {
safelist: [
"bg-blue-300",
"bg-orange-300",
"bg-rose-300",
"bg-fuchsia-300",
"bg-green-400",
"bg-purple-400",
"bg-orange-400",

View File

@@ -5,38 +5,19 @@
<turbo-stream action="append" target="active_downloads">
<template>
<tr data-download-list-target="download" id="ad_download_{{ entity.id }}">
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-stone-800 min-w-[45ch] max-w-[45ch] truncate">
{{ entity.title }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-gray-50">
{% if entity.progress < 100 %}
<div class="w-[3.25ch] h-[3.25ch] bg-purple-600 rounded-full block text-center table-cell align-middle text-xs text-gray-50">
{{ entity.progress }}
</div>
{% else %}
<twig:StatusBadge color="green" status="Complete" />
{% endif %}
</td>
<td></td>
</tr>
<twig:DownloadListRow download="{{ entity }}" isBroadcasted="true" />
</template>
</turbo-stream>
{% endblock %}
{% block update %}
{% if entity.status != "Complete" %}
<turbo-stream action="update" target="ad_download_{{ id }}">
<turbo-stream action="update" target="download_progress_{{ id }}">
<template>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-stone-800 min-w-[45ch] max-w-[45ch] truncate">
{{ entity.title }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-end text-gray-800 dark:text-gray-50">
<div class="border-2 border-green-700 rounded-md w-full h-6 align-middle overflow-hidden">
<div class="text-green-700 rounded-sm text-bold text-gray-950 text-center bg-green-600 h-5" style="width:{{ entity.progress }}%">{{ entity.progress }}%</div>
</div>
</td>
<td></td>
<div class="text-green-700 rounded-sm text-bold text-gray-950 text-center bg-green-600 h-5"
style="width:{{ entity.progress }}%">
<span>{{ entity.progress }}%</span>
</div>
</template>
</turbo-stream>
{% else %}
@@ -54,23 +35,7 @@
<turbo-stream action="prepend" target="complete_downloads">
<template>
<tr id="ad_download_{{ entity.id }}">
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-stone-800 min-w-[45ch] max-w-[45ch] truncate">
{{ entity.title }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-gray-50">
<twig:StatusBadge color="green" status="Complete" />
</td>
<td class="px-6 py-4 flex flex-row align-middle justify-center">
<button {{ stimulus_action('download_list', 'deleteDownload', 'click', {id: download.id}) }}>
<twig:ux:icon
name="ic:twotone-cancel" width="18px"
class="rounded-full align-middle text-red-600"
title="Remove {{ download.title }} from download list. This will not delete the file."
/>
</button>
</td>
</tr>
<twig:DownloadListRow download="{{ entity }}" :isBroadcasted="true" />
</template>
</turbo-stream>
{% endif %}

View File

@@ -3,83 +3,27 @@
<turbo-stream action="remove" target="active_monitors_no_monitors">
</turbo-stream>
<turbo-stream action="append" target="monitors">
<turbo-stream action="prepend" target="monitors">
<template>
<tr id="monitor_{{ entity.id }}">
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-stone-800 min-w-[50ch] max-w-[50ch] truncate">
{{ entity.title }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{{ entity.searchCount }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{{ entity.createdAt|date('m/d/Y h:i a') }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{{ entity.lastSearch|date('m/d/Y h:i a') }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{% if entity.status == "New" %}
<twig:StatusBadge color="orange" status="{{ entity.status }}" />
{% elseif entity.status == "In Progress" or entity.status == "Active" %}
<twig:StatusBadge color="purple" status="{{ entity.status }}" />
{% else %}
<twig:StatusBadge color="green" status="{{ entity.status }}" />
{% endif %}
</td>
<td class="px-6 py-4 flex flex-row align-middle justify-center">
<button {{ stimulus_action('monitor_list', 'deleteMonitor', 'click', {id: entity.id}) }}>
<twig:ux:icon
name="ic:twotone-cancel" width="18px"
class="rounded-full align-middle text-red-600"
title="Remove {{ entity.title }} from your Monitor list."
/>
</button>
</td>
</tr>
<twig:MonitorListRow monitor="{{ entity }}" />
</template>
</turbo-stream>
{% endblock %}
{% block update %}
<turbo-stream action="prepend" target="monitors">
<template>
<tr id="monitor_{{ entity.id }}">
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-stone-800 min-w-[50ch] max-w-[50ch] truncate">
{{ entity.title }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{{ entity.searchCount }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{{ entity.createdAt|date('m/d/Y h:i a') }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{{ entity.lastSearch|date('m/d/Y h:i a') }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{% if entity.status == "New" %}
<twig:StatusBadge color="orange" status="{{ entity.status }}" />
{% elseif entity.status == "In Progress" or entity.status == "Active" %}
<twig:StatusBadge color="purple" status="{{ entity.status }}" />
{% else %}
<twig:StatusBadge color="green" status="{{ entity.status }}" />
{% endif %}
</td>
<td class="px-6 py-4 flex flex-row align-middle justify-center">
<button {{ stimulus_action('monitor_list', 'deleteMonitor', 'click', {id: entity.id}) }}>
<twig:ux:icon
name="ic:twotone-cancel" width="18px"
class="rounded-full align-middle text-red-600"
title="Remove {{ entity.title }} from your Monitor list."
/>
</button>
</td>
</tr>
</template>
</turbo-stream>
<turbo-stream action="replace" target="monitor_{{ id }}">
<template>
<twig:MonitorListRow monitor="{{ entity }}" />
</template>
</turbo-stream>
{% endblock %}
{% block remove %}
<turbo-stream action="remove" target="monitor_{{ id }}"></turbo-stream>
<turbo-stream action="prepend" target="alert_list">
<template>
<twig:Alert title="Success" message="Your Monitor for '{{ entity.title }}' has been removed." alert_id="monitor_alert_{{ entity.id }}" data-controller="alert" />
</template>
</turbo-stream>
{% endblock %}

View File

@@ -1,5 +1,11 @@
<div{{ attributes.defaults(stimulus_controller('download_list')) }} class="min-w-48" >
<div{{ attributes.defaults(stimulus_controller('download_list', {isWidget: this.isWidget, perPage: this.perPage})) }} class="min-w-48" >
{% set table_body_id = (type == "complete") ? "complete_downloads" : "active_downloads" %}
{% if this.isWidget == true and this.downloads.items|length > this.perPage %}
{% set show_view_all = true %}
{% else %}
{% set show_view_all = false %}
{% endif %}
<table id="downloads" class="divide-y divide-gray-200 bg-gray-50 overflow-hidden rounded-lg table-auto w-full" {{ turbo_stream_listen('App\\Download\\Framework\\Entity\\Download') }}>
<thead>
<tr class="bg-orange-500 bg-filter bg-blur-lg bg-opacity-80 text-gray-950">
@@ -31,50 +37,13 @@
<tbody id="{{ table_body_id }}" class="divide-y divide-gray-200 dark:divide-gray-50">
{% if this.downloads.items|length > 0 %}
{% for download in this.downloads.items %}
<tr id="ad_download_{{ download.id }}">
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-stone-800 {% if this.isWidget == true %}min-w-[45ch] max-w-[45ch]{% endif %} truncate">
{{ download.title }}
</td>
{% if this.isWidget == false %}
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-stone-800 truncate">
{{ download.filename }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-stone-800 truncate">
{{ download.mediaType }}
</td>
{% endif %}
<td class="px-6 py-4 whitespace-nowrap text-sm align-middle text-gray-800 dark:text-gray-50">
{% if download.progress < 100 %}
<div class="border-2 border-green-700 rounded-md w-full h-6 align-middle overflow-hidden">
<div class="text-green-700 rounded-sm text-bold text-gray-950 text-center bg-green-600 h-5"
style="width:{{ download.progress }}%">
{{ download.progress }}%
</div>
</div>
{% else %}
<twig:StatusBadge color="green" status="Complete" />
{% endif %}
</td>
<td class="px-6 py-4 flex flex-row align-middle justify-center">
<button {{ stimulus_action('download_list', 'deleteDownload', 'click', {id: download.id}) }}>
<twig:ux:icon
name="ic:twotone-cancel" width="18px"
class="rounded-full align-middle text-red-600"
title="Remove {{ download.title }} from your Download list. This will not delete the file."
/>
</button>
</td>
</tr>
<twig:DownloadListRow download="{{ download }}" isWidget="{{ this.isWidget }}" perPage="{{ this.perPage }}" />
{% endfor %}
{% if this.isWidget == true and this.downloads.items|length > this.perPage %}
<tr id="download_view_all">
<td class="py-2 whitespace-nowrap bg-orange-300 uppercase text-xs font-medium text-center text-black truncate" colspan="100%">
<a href="{{ path('app_downloads') }}">View All Downloads</a>
</td>
</tr>
{% endif %}
<tr id="download_view_all" class="{{ show_view_all == false ?? "hidden" }}" {{ stimulus_target('download_list', 'viewAllBtn')}} >
<td class="py-2 whitespace-nowrap bg-orange-300 uppercase text-xs font-medium text-center text-black truncate" colspan="100%">
<a href="{{ path('app_downloads') }}">View All Downloads</a>
</td>
</tr>
{% else %}
<tr id="{{ table_body_id }}_no_downloads">
<td class="px-6 py-4 whitespace-nowrap text-xs uppercase text-center font-medium text-gray-800 dark:text-stone-800" colspan="100%">

View File

@@ -0,0 +1,36 @@
<tr{{ attributes }} id="ad_download_{{ download.id }}" {{ stimulus_target('download_list', 'downloadRow') }} isBroadcasted="{{ isBroadcasted ?? 'false' }}">
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-stone-800 truncate">
{{ download.title }}
</td>
{% if isWidget == false %}
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-stone-800 max-w-[60ch] truncate">
{{ download.filename }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-stone-800 truncate">
{{ download.mediaType }}
</td>
{% endif %}
<td class="px-6 py-4 whitespace-nowrap text-sm align-middle text-gray-800 dark:text-gray-50">
{% if download.progress < 100 %}
<div id="download_progress_{{ download.id }}" class="border-2 border-green-600 rounded-md text-center w-full h-6 align-middle overflow-hidden">
<div class="text-black text-center rounded-sm text-bold bg-green-300 h-5 relative z-10"
style="width:{{ download.progress }}%">
</div>
<div class="absolute text-black text-center" style="z-index: 400;margin-top: -1.25rem; margin-left: 1.2rem">{{ download.progress }}%</div>
</div>
{% else %}
<twig:StatusBadge color="green" status="Complete" />
{% endif %}
</td>
<td class="px-6 py-4 flex flex-row align-middle justify-center">
<button {{ stimulus_action('download_list', 'deleteDownload', 'click', {id: download.id}) }}>
<twig:ux:icon
name="ic:twotone-cancel" width="18px"
class="rounded-full align-middle text-red-600"
title="Remove {{ download.title }} from your Download list. This will not delete the file."
/>
</button>
</td>
</tr>

View File

@@ -36,50 +36,7 @@
<tbody id="monitors" class="divide-y divide-gray-50">
{% if this.monitors.items|length > 0 %}
{% for monitor in this.monitors.items %}
<tr id="monitor_{{ monitor.id }}">
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-stone-800 truncate">
{{ monitor.title }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{{ monitor|monitor_media_id }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{{ monitor.searchCount }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{{ monitor.createdAt|date('m/d/Y h:i a') }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{{ monitor.lastSearch|date('m/d/Y h:i a') }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{% if monitor.monitorType == "tvshow" %}
<twig:StatusBadge color="blue" number="300" text="black" status="{{ monitor.monitorType|monitor_type }}" />
{% elseif monitor.monitorType == "tvseason" %}
<twig:StatusBadge color="orange" number="300" text="black" status="{{ monitor.monitorType|monitor_type }}" />
{% else %}
<twig:StatusBadge color="rose" number="300" text="black" status="{{ monitor.monitorType|monitor_type }}" />
{% endif %}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{% if monitor.status == "New" %}
<twig:StatusBadge color="orange" status="{{ monitor.status }}" />
{% elseif monitor.status == "In Progress" or monitor.status == "Active" %}
<twig:StatusBadge color="purple" status="{{ monitor.status }}" />
{% else %}
<twig:StatusBadge color="green" status="{{ monitor.status }}" />
{% endif %}
</td>
<td class="px-6 py-4 flex flex-row align-middle justify-center">
<button {{ stimulus_action('monitor_list', 'deleteMonitor', 'click', {id: monitor.id}) }}>
<twig:ux:icon
name="ic:twotone-cancel" width="18px"
class="rounded-full align-middle text-red-600"
title="Remove {{ monitor.title }} from your Monitor list."
/>
</button>
</td>
</tr>
<twig:MonitorListRow :monitor="monitor" />
{% endfor %}
{% if this.isWidget and this.monitors.items|length > 5 %}
<tr id="monitor_view_all">

View File

@@ -0,0 +1,44 @@
<tr{{ attributes }} id="monitor_{{ monitor.id }}">
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-stone-800 truncate">
{{ monitor.title }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{{ monitor|monitor_media_id }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{{ monitor.searchCount }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{{ monitor.createdAt|date('m/d/Y h:i a') }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{{ monitor.lastSearch|date('m/d/Y h:i a') }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{% if monitor.monitorType == "tvshow" %}
<twig:StatusBadge color="blue" number="300" text="black" status="{{ monitor.monitorType|monitor_type }}" />
{% elseif monitor.monitorType == "tvseason" %}
<twig:StatusBadge color="orange" number="300" text="black" status="{{ monitor.monitorType|monitor_type }}" />
{% else %}
<twig:StatusBadge color="fuchsia" number="300" text="black" status="{{ monitor.monitorType|monitor_type }}" />
{% endif %}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
{% if monitor.status == "New" %}
<twig:StatusBadge color="orange" status="{{ monitor.status }}" />
{% elseif monitor.status == "In Progress" or monitor.status == "Active" %}
<twig:StatusBadge color="purple" status="{{ monitor.status }}" />
{% else %}
<twig:StatusBadge color="green" status="{{ monitor.status }}" />
{% endif %}
</td>
<td class="px-6 py-4 flex flex-row align-middle justify-center">
<button {{ stimulus_action('monitor_list', 'deleteMonitor', 'click', {id: monitor.id}) }}>
<twig:ux:icon
name="ic:twotone-cancel" width="18px"
class="rounded-full align-middle text-red-600"
title="Remove {{ monitor.title }} from your Monitor list."
/>
</button>
</td>
</tr>