Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5094b31ce6 | |||
| 768318b43a | |||
| e4db24ee8d | |||
| 2bed04cd18 |
@@ -3,7 +3,9 @@
|
|||||||
"type": "userfrosting-sprinkle",
|
"type": "userfrosting-sprinkle",
|
||||||
"description": "A sprinkle to add scheduled events.",
|
"description": "A sprinkle to add scheduled events.",
|
||||||
"require": {
|
"require": {
|
||||||
"dragonmantank/cron-expression": "*"
|
"dragonmantank/cron-expression": "*",
|
||||||
|
"lorisleiva/cron-translator": "^0.3.2",
|
||||||
|
"twig/intl-extra": "^3.6"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"files" : [
|
"files" : [
|
||||||
@@ -13,4 +15,4 @@
|
|||||||
"UserFrosting\\Sprinkle\\Scheduler\\": "src/"
|
"UserFrosting\\Sprinkle\\Scheduler\\": "src/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
locale/en_US/messages.php
Normal file
27
locale/en_US/messages.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AVSDev UF Scheduler (https://avsdev.uk)
|
||||||
|
*
|
||||||
|
* @link https://git.avsdev.uk/avsdev/sprinkle-scheduler
|
||||||
|
* @license https://git.avsdev.uk/avsdev/sprinkle-scheduler/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* US English message token translations for the 'scheduler' sprinkle.
|
||||||
|
*
|
||||||
|
* @author Craig Williams
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
'TASK' => [
|
||||||
|
1 => 'Task',
|
||||||
|
2 => 'Tasks',
|
||||||
|
|
||||||
|
'NAME' => 'Task name',
|
||||||
|
'PAGE_DESCRIPTION' => 'This page shows a list of programmed tasks that the UserFrosting Scheduler sprinkle knows about, their schedules and when they are next expected to run.',
|
||||||
|
],
|
||||||
|
|
||||||
|
'SPRINKLE' => 'Sprinkle',
|
||||||
|
'SCHEDULE' => 'Schedule',
|
||||||
|
'NEXT_RUN_TIME' => 'Next run time',
|
||||||
|
];
|
||||||
22
routes/tasks.php
Normal file
22
routes/tasks.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AVSDev UF Scheduler (https://avsdev.uk)
|
||||||
|
*
|
||||||
|
* @link https://git.avsdev.uk/avsdev/sprinkle-scheduler
|
||||||
|
* @license https://git.avsdev.uk/avsdev/sprinkle-scheduler/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||||
|
*/
|
||||||
|
|
||||||
|
use UserFrosting\Sprinkle\Core\Util\NoCache;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Routes for schdeuled task listing.
|
||||||
|
*/
|
||||||
|
$app->group('/tasks', function () {
|
||||||
|
$this->get('', 'UserFrosting\Sprinkle\Scheduler\Controller\TaskController:pageList')
|
||||||
|
->setName('uri_permissions');
|
||||||
|
})->add('authGuard')->add(new NoCache());
|
||||||
|
|
||||||
|
$app->group('/api/tasks', function () {
|
||||||
|
$this->get('', 'UserFrosting\Sprinkle\Scheduler\Controller\TaskController:getList');
|
||||||
|
})->add('authGuard')->add(new NoCache());
|
||||||
@@ -110,6 +110,5 @@ class ScheduleCommand extends BaseCommand
|
|||||||
$this->io->error('Schedule failed !');
|
$this->io->error('Schedule failed !');
|
||||||
return self::FAILURE;
|
return self::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
110
src/Controller/TaskController.php
Normal file
110
src/Controller/TaskController.php
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AVSDev UF Scheduler (https://avsdev.uk)
|
||||||
|
*
|
||||||
|
* @link https://git.avsdev.uk/avsdev/sprinkle-scheduler
|
||||||
|
* @license https://git.avsdev.uk/avsdev/sprinkle-scheduler/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace UserFrosting\Sprinkle\Scheduler\Controller;
|
||||||
|
|
||||||
|
use Psr\Http\Message\ResponseInterface as Response;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||||
|
use UserFrosting\Sprinkle\Core\Controller\SimpleController;
|
||||||
|
use UserFrosting\Support\Exception\ForbiddenException;
|
||||||
|
use UserFrosting\Support\Exception\NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller class for task-related requests, (listing tasks).
|
||||||
|
*
|
||||||
|
* @author Craig Williams (https://avsdev.uk)
|
||||||
|
*/
|
||||||
|
class TaskController extends SimpleController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns a list of Tasks.
|
||||||
|
*
|
||||||
|
* Generates a list of tasks from the scehduler. No sorting or pagination functionality.
|
||||||
|
* This page requires authentication.
|
||||||
|
*
|
||||||
|
* Request type: GET
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
*
|
||||||
|
* @throws ForbiddenException If user is not authorized to access page
|
||||||
|
*/
|
||||||
|
public function getList(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
// GET parameters
|
||||||
|
$params = $request->getQueryParams();
|
||||||
|
|
||||||
|
/** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager */
|
||||||
|
$authorizer = $this->ci->authorizer;
|
||||||
|
|
||||||
|
/** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */
|
||||||
|
$currentUser = $this->ci->currentUser;
|
||||||
|
|
||||||
|
// Access-controlled page
|
||||||
|
if (!$authorizer->checkAccess($currentUser, 'uri_tasks')) {
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var \UserFrosting\Sprinkle\Scheduler\Scheduler $scheduler */
|
||||||
|
$scheduler = $this->ci->scheduler;
|
||||||
|
|
||||||
|
$tasks = $scheduler->getTasks();
|
||||||
|
|
||||||
|
$tasks = array_map(
|
||||||
|
function($val) {
|
||||||
|
$val['schedule_nice'] = CronTranslator::translate($val['schedule']);
|
||||||
|
return $val;
|
||||||
|
},
|
||||||
|
$tasks
|
||||||
|
);
|
||||||
|
|
||||||
|
// Be careful how you consume this data - it has not been escaped and contains untrusted user-supplied content.
|
||||||
|
// For example, if you plan to insert it into an HTML DOM, you must escape it on the client side (or use client-side templating).
|
||||||
|
return $response->withJson($tasks, 200, JSON_PRETTY_PRINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the task listing page.
|
||||||
|
*
|
||||||
|
* This page renders a table of tasks, with dropdown menus for admin actions for each task.
|
||||||
|
* Actions typically include: run task
|
||||||
|
* This page requires authentication.
|
||||||
|
*
|
||||||
|
* Request type: GET
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
*
|
||||||
|
* @throws ForbiddenException If user is not authorized to access page
|
||||||
|
*/
|
||||||
|
public function pageList(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
/** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager */
|
||||||
|
$authorizer = $this->ci->authorizer;
|
||||||
|
|
||||||
|
/** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */
|
||||||
|
$currentUser = $this->ci->currentUser;
|
||||||
|
|
||||||
|
// Access-controlled page
|
||||||
|
if (!$authorizer->checkAccess($currentUser, 'uri_tasks')) {
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var \UserFrosting\Sprinkle\Scheduler\Scheduler $scheduler */
|
||||||
|
$scheduler = $this->ci->scheduler;
|
||||||
|
|
||||||
|
$tasks = $scheduler->getTasks();
|
||||||
|
|
||||||
|
return $this->ci->view->render($response, 'pages/tasks.html.twig', [
|
||||||
|
'tasks' => $tasks
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/Database/Seeds/SchedulerPermissions.php
Normal file
95
src/Database/Seeds/SchedulerPermissions.php
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AVSDev UF Scheduler (https://avsdev.uk)
|
||||||
|
*
|
||||||
|
* @link https://git.avsdev.uk/avsdev/sprinkle-scheduler
|
||||||
|
* @license https://git.avsdev.uk/avsdev/sprinkle-scheduler/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace UserFrosting\Sprinkle\Scheduler\Database\Seeds;
|
||||||
|
|
||||||
|
use UserFrosting\Sprinkle\Account\Database\Models\Permission;
|
||||||
|
use UserFrosting\Sprinkle\Account\Database\Models\Role;
|
||||||
|
use UserFrosting\Sprinkle\Core\Database\Seeder\BaseSeed;
|
||||||
|
use UserFrosting\Sprinkle\Core\Facades\Seeder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seeder for the dashboard permissions.
|
||||||
|
*/
|
||||||
|
class SchedulerPermissions extends BaseSeed
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
// We require the default roles
|
||||||
|
Seeder::execute('DefaultRoles');
|
||||||
|
|
||||||
|
// Get and save permissions
|
||||||
|
$permissions = $this->getPermissions();
|
||||||
|
$this->savePermissions($permissions);
|
||||||
|
|
||||||
|
// Add default mappings to permissions
|
||||||
|
$this->syncPermissionsRole($permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array Permissions to seed
|
||||||
|
*/
|
||||||
|
protected function getPermissions()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'uri_task' => new Permission([
|
||||||
|
'slug' => 'uri_task',
|
||||||
|
'name' => 'View task',
|
||||||
|
'conditions' => 'always()',
|
||||||
|
'description' => 'View the task page of any task.',
|
||||||
|
]),
|
||||||
|
'uri_tasks' => new Permission([
|
||||||
|
'slug' => 'uri_tasks',
|
||||||
|
'name' => 'Tasks management page',
|
||||||
|
'conditions' => 'always()',
|
||||||
|
'description' => 'View a page containing a table of tasks.',
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save permissions.
|
||||||
|
*
|
||||||
|
* @param array $permissions
|
||||||
|
*/
|
||||||
|
protected function savePermissions(array &$permissions)
|
||||||
|
{
|
||||||
|
foreach ($permissions as $slug => $permission) {
|
||||||
|
// Trying to find if the permission already exist
|
||||||
|
$existingPermission = Permission::where(['slug' => $permission->slug, 'conditions' => $permission->conditions])->first();
|
||||||
|
|
||||||
|
// Don't save if already exist, use existing permission reference
|
||||||
|
// otherwise to re-sync permissions and roles
|
||||||
|
if ($existingPermission == null) {
|
||||||
|
$permission->save();
|
||||||
|
} else {
|
||||||
|
$permissions[$slug] = $existingPermission;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sync permissions with default roles.
|
||||||
|
*
|
||||||
|
* @param array $permissions
|
||||||
|
*/
|
||||||
|
protected function syncPermissionsRole(array $permissions)
|
||||||
|
{
|
||||||
|
$roleSiteAdmin = Role::where('slug', 'site-admin')->first();
|
||||||
|
if ($roleSiteAdmin) {
|
||||||
|
$roleSiteAdmin->permissions()->syncWithoutDetaching([
|
||||||
|
$permissions['uri_tasks']->id,
|
||||||
|
$permissions['uri_task']->id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -179,15 +179,19 @@ class Scheduler
|
|||||||
*/
|
*/
|
||||||
protected function getTaskDetails(ResourceInstance $file)
|
protected function getTaskDetails(ResourceInstance $file)
|
||||||
{
|
{
|
||||||
|
/** @var \UserFrosting\System\Sprinkle\SprinkleManager */
|
||||||
|
$sprinkleManager = $this->ci->sprinkleManager;
|
||||||
|
|
||||||
// Format the sprinkle name for the namespace
|
// Format the sprinkle name for the namespace
|
||||||
$sprinkleName = $file->getLocation()->getName();
|
$sprinkleName = $file->getLocation()->getName();
|
||||||
$sprinkleName = Str::studly($sprinkleName);
|
$sprinkleNS = $sprinkleManager->getSprinkleClassNamespace($sprinkleName);
|
||||||
|
|
||||||
|
|
||||||
// Getting base path, name and class name
|
// Getting base path, name and class name
|
||||||
$basePath = str_replace($file->getBasename(), '', $file->getBasePath());
|
$basePath = str_replace($file->getBasename(), '', $file->getBasePath());
|
||||||
$name = $basePath . $file->getFilename();
|
$name = $basePath . $file->getFilename();
|
||||||
$className = str_replace('/', '\\', $basePath) . $file->getFilename();
|
$className = str_replace('/', '\\', $basePath) . $file->getFilename();
|
||||||
$classPath = "\\UserFrosting\\Sprinkle\\$sprinkleName\\Scheduler\\Tasks\\$className";
|
$classPath = "\\$sprinkleNS\\Scheduler\\Tasks\\$className";
|
||||||
|
|
||||||
if (!class_exists($classPath)) {
|
if (!class_exists($classPath)) {
|
||||||
throw new \Exception("Task class `$className` not found. Make sure the class has the correct namespace.");
|
throw new \Exception("Task class `$className` not found. Make sure the class has the correct namespace.");
|
||||||
|
|||||||
@@ -11,8 +11,11 @@ namespace UserFrosting\Sprinkle\Scheduler\ServicesProvider;
|
|||||||
|
|
||||||
use Illuminate\Container\Container;
|
use Illuminate\Container\Container;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
use UserFrosting\Sprinkle\Scheduler\Scheduler\Scheduler;
|
use Twig\Extra\Intl\IntlExtension;
|
||||||
use UserFrosting\Sprinkle\Core\ServicesProvider\BaseServicesProvider;
|
use UserFrosting\Sprinkle\Core\ServicesProvider\BaseServicesProvider;
|
||||||
|
use UserFrosting\Sprinkle\Scheduler\Scheduler\Scheduler;
|
||||||
|
use UserFrosting\Sprinkle\Scheduler\Twig\FormatCronExtension;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sheduler services provider.
|
* Sheduler services provider.
|
||||||
@@ -38,5 +41,21 @@ class ServicesProvider
|
|||||||
$container['scheduler'] = function ($c) {
|
$container['scheduler'] = function ($c) {
|
||||||
return new Scheduler($c);
|
return new Scheduler($c);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extends the 'view' service with the HasRole extension for Twig.
|
||||||
|
*
|
||||||
|
* @return \Slim\Views\Twig
|
||||||
|
*/
|
||||||
|
$container->extend('view', function ($view, $c) {
|
||||||
|
$twig = $view->getEnvironment();
|
||||||
|
|
||||||
|
if (!$twig->hasExtension('Twig\Extra\Intl\IntlExtension')) {
|
||||||
|
$twig->addExtension(new IntlExtension());
|
||||||
|
}
|
||||||
|
$twig->addExtension(new FormatCronExtension($c));
|
||||||
|
|
||||||
|
return $view;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
64
src/Twig/FormatCronExtension.php
Normal file
64
src/Twig/FormatCronExtension.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AVSDev UF Scheduler (https://avsdev.uk)
|
||||||
|
*
|
||||||
|
* @link https://git.avsdev.uk/avsdev/sprinkle-scheduler
|
||||||
|
* @license https://git.avsdev.uk/avsdev/sprinkle-scheduler/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace UserFrosting\Sprinkle\Scheduler\Twig;
|
||||||
|
|
||||||
|
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||||
|
use Lorisleiva\CronTranslator\CronTranslator;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
use Twig\Extension\AbstractExtension;
|
||||||
|
use Twig\Extension\GlobalsInterface;
|
||||||
|
use Twig\TwigFilter;
|
||||||
|
use UserFrosting\Support\Repository\Repository as Config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends Twig functionality to add formatCron.
|
||||||
|
*
|
||||||
|
* @author Craig Williams (https://avsdev.uk)
|
||||||
|
*/
|
||||||
|
class FormatCronExtension extends AbstractExtension implements GlobalsInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ContainerInterface
|
||||||
|
*/
|
||||||
|
protected $services;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Config
|
||||||
|
*/
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ContainerInterface $services
|
||||||
|
*/
|
||||||
|
public function __construct(ContainerInterface $services)
|
||||||
|
{
|
||||||
|
$this->services = $services;
|
||||||
|
$this->config = $services->config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'avsdev/schedule-formatCron';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFilters()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new TwigFilter('formatCron', function ($cron) {
|
||||||
|
return CronTranslator::translate($cron);
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGlobals()
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
5
templates/navigation/partials/sidebar-tasks.html.twig
Normal file
5
templates/navigation/partials/sidebar-tasks.html.twig
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{% if checkAccess('uri_tasks') %}
|
||||||
|
<li>
|
||||||
|
<a href="{{site.uri.public}}/tasks"><i class="fas fa-tasks fa-fw"></i> <span>{{ translate("TASK", 2) }}</span></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
6
templates/navigation/sidebar-menu.html.twig
Normal file
6
templates/navigation/sidebar-menu.html.twig
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{% extends "@admin/navigation/sidebar-menu.html.twig" %}
|
||||||
|
|
||||||
|
{% block navigation %}
|
||||||
|
{{ parent() }}
|
||||||
|
{% include "navigation/partials/sidebar-tasks.html.twig" %}
|
||||||
|
{% endblock %}
|
||||||
41
templates/pages/tasks.html.twig
Normal file
41
templates/pages/tasks.html.twig
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{% extends "pages/abstract/dashboard.html.twig" %}
|
||||||
|
|
||||||
|
{% block stylesheets_page %}
|
||||||
|
<!-- Page-specific CSS asset bundle -->
|
||||||
|
{{ assets.css('css/form-widgets') | raw }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{# Overrides blocks in head of base template #}
|
||||||
|
{% block page_title %}{{ translate("TASK", 2)}}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_description %}{{ translate("TASK.PAGE_DESCRIPTION")}}{% endblock %}
|
||||||
|
|
||||||
|
{% block body_matter %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div id="widget-tasks" class="box box-primary">
|
||||||
|
<div class="box-header">
|
||||||
|
<h3 class="box-title pull-left"><i class="fas fa-tasks fa-fw"></i> {{translate('TASK', 2)}}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="box-body">
|
||||||
|
{% include "tables/tasks.html.twig" with {
|
||||||
|
"table" : {
|
||||||
|
"id" : "table-tasks"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block scripts_page %}
|
||||||
|
<!-- Include validation rules -->
|
||||||
|
<script>
|
||||||
|
{% include "pages/partials/page.js.twig" %}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Include form widgets JS -->
|
||||||
|
{{ assets.js('js/form-widgets') | raw }}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
49
templates/tables/tasks.html.twig
Normal file
49
templates/tables/tasks.html.twig
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{# This partial template renders a table of permissions, to be populated with rows via an AJAX request.
|
||||||
|
# This extends a generic template for paginated tables.
|
||||||
|
#
|
||||||
|
# Note that this template contains a "skeleton" table with an empty table body, and then a block of Handlebars templates which are used
|
||||||
|
# to render the table cells with the data from the AJAX request.
|
||||||
|
#}
|
||||||
|
|
||||||
|
{% extends "tables/table-paginated.html.twig" %}
|
||||||
|
|
||||||
|
{% block table %}
|
||||||
|
<table id="{{table.id}}" class="tablesorter table table-bordered table-hover table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th data-column-name="name" data-priority="1">{{translate('NAME')}}</th>
|
||||||
|
<th data-column-name="sprinkle" data-priority="1">{{translate('SPRINKLE')}}</th>
|
||||||
|
<th data-column-name="schedule" data-priority="1">{{translate('SCHEDULE')}}</th>
|
||||||
|
<th data-column-name="next_run" data-priority="1">{{translate('NEXT_RUN_TIME')}}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for task in tasks %}
|
||||||
|
<tr>
|
||||||
|
<td data-text="{{task.sprinkle}}/{{task.name}}">
|
||||||
|
<div>
|
||||||
|
<strong>
|
||||||
|
<!--<a href="{{site.uri.public}}/tasks/t/{{task.sprinkle}}/{{task.name}}">{{task.name}}</a>-->
|
||||||
|
{{task.name}}
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td data-text="{{task.sprinkle}}">
|
||||||
|
{{task.sprinkle}}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td data-text="{{task.schedule}}">
|
||||||
|
<i class="text-muted" style="min-width: 70px; display: inline-block">({{task.schedule}})</i> {{task.schedule | formatCron()}}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td data-text="{{task.next_run}}">
|
||||||
|
{{ task.next_run | format_datetime(pattern='HH:mm:ss dd/MM/yyyy') }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block table_pager_controls %}{% endblock %}
|
||||||
Reference in New Issue
Block a user