mirror of
https://github.com/Karaka-Management/oms-Workflow.git
synced 2026-02-14 21:08:41 +00:00
workflow drafting
This commit is contained in:
parent
79ce5a03be
commit
e642592ac1
|
|
@ -63,6 +63,17 @@
|
||||||
"primary": true,
|
"primary": true,
|
||||||
"autoincrement": true
|
"autoincrement": true
|
||||||
},
|
},
|
||||||
|
"workflow_instance_title": {
|
||||||
|
"name": "workflow_instance_title",
|
||||||
|
"type": "VARCHAR(255)",
|
||||||
|
"default": null,
|
||||||
|
"null": true
|
||||||
|
},
|
||||||
|
"workflow_instance_status": {
|
||||||
|
"name": "workflow_instance_status",
|
||||||
|
"type": "INT",
|
||||||
|
"null": false
|
||||||
|
},
|
||||||
"workflow_instance_template": {
|
"workflow_instance_template": {
|
||||||
"name": "workflow_instance_template",
|
"name": "workflow_instance_template",
|
||||||
"type": "INT",
|
"type": "INT",
|
||||||
|
|
|
||||||
26
Controller.js
Normal file
26
Controller.js
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { Autoloader } from '../../jsOMS/Autoloader.js';
|
||||||
|
|
||||||
|
Autoloader.defineNamespace('jsOMS.Modules');
|
||||||
|
|
||||||
|
jsOMS.Modules.Workflow = class {
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
constructor (app)
|
||||||
|
{
|
||||||
|
this.app = app;
|
||||||
|
};
|
||||||
|
|
||||||
|
bind (id)
|
||||||
|
{
|
||||||
|
mermaid.initialize({startOnLoad:true});
|
||||||
|
};
|
||||||
|
|
||||||
|
bindElement (chart)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
window.omsApp.moduleManager.get('Workflow').bind();
|
||||||
|
|
@ -21,6 +21,7 @@ use Modules\Media\Models\NullMedia;
|
||||||
use Modules\Media\Models\PathSettings;
|
use Modules\Media\Models\PathSettings;
|
||||||
use Modules\Workflow\Models\PermissionCategory;
|
use Modules\Workflow\Models\PermissionCategory;
|
||||||
use Modules\Workflow\Models\WorkflowInstanceAbstract;
|
use Modules\Workflow\Models\WorkflowInstanceAbstract;
|
||||||
|
use Modules\Workflow\Models\WorkflowInstanceAbstractMapper;
|
||||||
use Modules\Workflow\Models\WorkflowStatus;
|
use Modules\Workflow\Models\WorkflowStatus;
|
||||||
use Modules\Workflow\Models\WorkflowTemplate;
|
use Modules\Workflow\Models\WorkflowTemplate;
|
||||||
use Modules\Workflow\Models\WorkflowTemplateMapper;
|
use Modules\Workflow\Models\WorkflowTemplateMapper;
|
||||||
|
|
@ -146,7 +147,7 @@ final class ApiController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var WorkflowInstanceAbstract $instance */
|
/** @var WorkflowInstanceAbstract $instance */
|
||||||
$instance = WorkflowInstanceMapper::get()
|
$instance = WorkflowInstanceAbstractMapper::get()
|
||||||
->with('template')
|
->with('template')
|
||||||
->with('template/source')
|
->with('template/source')
|
||||||
->with('template/source/sources')
|
->with('template/source/sources')
|
||||||
|
|
@ -602,18 +603,19 @@ final class ApiController extends Controller
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var \Modules\Workflow\Models\WorkflowTemplate $template */
|
||||||
$template = WorkflowTemplateMapper::get()
|
$template = WorkflowTemplateMapper::get()
|
||||||
->where('id', (int) $request->getData('id'))
|
->with('source')
|
||||||
|
->with('source/sources')
|
||||||
|
->where('id', (int) $request->getData('template'))
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
$instance = $this->createInstanceFromRequest($template, $request);
|
$instance = $this->createInstanceFromRequest($request, $template);
|
||||||
|
|
||||||
require_once $template->findFile('WorkflowInstanceMapper.php')->getPath();
|
|
||||||
|
|
||||||
$this->createModel(
|
$this->createModel(
|
||||||
$request->header->account,
|
$request->header->account,
|
||||||
$instance,
|
$instance,
|
||||||
\Modules\Workflow\Models\WorkflowInstanceMapper::class,
|
WorkflowInstanceAbstractMapper::class,
|
||||||
'instance',
|
'instance',
|
||||||
$request->getOrigin()
|
$request->getOrigin()
|
||||||
);
|
);
|
||||||
|
|
@ -632,7 +634,7 @@ final class ApiController extends Controller
|
||||||
private function validateInstanceCreate(RequestAbstract $request) : array
|
private function validateInstanceCreate(RequestAbstract $request) : array
|
||||||
{
|
{
|
||||||
$val = [];
|
$val = [];
|
||||||
if (($val['j'] = empty($request->getData('j')))) {
|
if (($val['template'] = empty($request->getData('template')))) {
|
||||||
return $val;
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -642,24 +644,24 @@ final class ApiController extends Controller
|
||||||
/**
|
/**
|
||||||
* Method to create interface from request.
|
* Method to create interface from request.
|
||||||
*
|
*
|
||||||
* @param WorkflowTemplate $template Workflow template
|
|
||||||
* @param RequestAbstract $request Request
|
* @param RequestAbstract $request Request
|
||||||
|
* @param WorkflowTemplate $template Workflow template
|
||||||
*
|
*
|
||||||
* @return WorkflowInstanceAbstract
|
* @return WorkflowInstanceAbstract
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
private function createInstanceFromRequest(WorkflowTemplate $template, RequestAbstract $request) : WorkflowInstanceAbstract
|
private function createInstanceFromRequest(RequestAbstract $request, WorkflowTemplate $template) : WorkflowInstanceAbstract
|
||||||
{
|
{
|
||||||
$controller = null;
|
$controller = null;
|
||||||
|
|
||||||
$file = $template->source->findFile('WorkflowController.php');
|
$file = $template->source->findFile('WorkflowController.php');
|
||||||
require_once $file->getPath();
|
require_once $file->getAbsolutePath();
|
||||||
|
|
||||||
$controller = new \Modules\Workflow\Controller\WorkflowController($this->app, $template);
|
|
||||||
|
|
||||||
/** @var \Modules\Workflow\Models\WorkflowControllerInterface $controller */
|
/** @var \Modules\Workflow\Models\WorkflowControllerInterface $controller */
|
||||||
$instance = $controller->createInstanceFromRequest($request);
|
$controller = new \Modules\Workflow\Controller\WorkflowController($this->app, $template);
|
||||||
|
|
||||||
|
$instance = $controller->createInstanceFromRequest($request, $template);
|
||||||
|
|
||||||
return $instance;
|
return $instance;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,10 @@ namespace Modules\Workflow\Controller;
|
||||||
use Modules\Media\Models\CollectionMapper;
|
use Modules\Media\Models\CollectionMapper;
|
||||||
use Modules\Media\Models\NullMedia;
|
use Modules\Media\Models\NullMedia;
|
||||||
use Modules\Workflow\Models\WorkflowControllerInterface;
|
use Modules\Workflow\Models\WorkflowControllerInterface;
|
||||||
|
use Modules\Workflow\Models\WorkflowInstanceAbstractMapper;
|
||||||
use Modules\Workflow\Models\WorkflowInstanceMapper;
|
use Modules\Workflow\Models\WorkflowInstanceMapper;
|
||||||
use Modules\Workflow\Models\WorkflowTemplateMapper;
|
use Modules\Workflow\Models\WorkflowTemplateMapper;
|
||||||
|
use phpOMS\Asset\AssetType;
|
||||||
use phpOMS\Contract\RenderableInterface;
|
use phpOMS\Contract\RenderableInterface;
|
||||||
use phpOMS\Message\RequestAbstract;
|
use phpOMS\Message\RequestAbstract;
|
||||||
use phpOMS\Message\ResponseAbstract;
|
use phpOMS\Message\ResponseAbstract;
|
||||||
|
|
@ -108,6 +110,10 @@ final class BackendController extends Controller
|
||||||
$view->setTemplate('/Modules/Workflow/Theme/Backend/workflow-profile');
|
$view->setTemplate('/Modules/Workflow/Theme/Backend/workflow-profile');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$head = $response->get('Content')->getData('head');
|
||||||
|
$head->addAsset(AssetType::JSLATE, 'Resources/mermaid/mermaid.min.js');
|
||||||
|
$head->addAsset(AssetType::JSLATE, 'Modules/Workflow/Controller.js', ['type' => 'module']);
|
||||||
|
|
||||||
return $view;
|
return $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,6 +156,11 @@ final class BackendController extends Controller
|
||||||
$view->setTemplate('/Modules/Workflow/Theme/Backend/workflow-dashboard');
|
$view->setTemplate('/Modules/Workflow/Theme/Backend/workflow-dashboard');
|
||||||
$view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1005501001, $request, $response));
|
$view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1005501001, $request, $response));
|
||||||
|
|
||||||
|
$instances = WorkflowInstanceAbstractMapper::getAll()
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$view->setData('instances', $instances);
|
||||||
|
|
||||||
return $view;
|
return $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,7 +182,8 @@ final class BackendController extends Controller
|
||||||
$view->setTemplate('/Modules/Workflow/Theme/Backend/workflow-instance-list');
|
$view->setTemplate('/Modules/Workflow/Theme/Backend/workflow-instance-list');
|
||||||
$view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1005501001, $request, $response));
|
$view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1005501001, $request, $response));
|
||||||
|
|
||||||
$instances = WorkflowInstanceMapper::getAll()
|
/** @var \Modules\Workflow\Models\WorkflowInstanceAbstract $instances */
|
||||||
|
$instances = WorkflowInstanceAbstractMapper::getAll()
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
$view->setData('instances', $instances);
|
$view->setData('instances', $instances);
|
||||||
|
|
@ -196,13 +208,21 @@ final class BackendController extends Controller
|
||||||
$view = new View($this->app->l11nManager, $request, $response);
|
$view = new View($this->app->l11nManager, $request, $response);
|
||||||
$view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1005501001, $request, $response));
|
$view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1005501001, $request, $response));
|
||||||
|
|
||||||
|
/** @var \Modules\Workflow\Models\WorkflowInstanceAbstract $instance */
|
||||||
|
$instance = WorkflowInstanceAbstractMapper::get()
|
||||||
|
->where('id', (int) $request->getData('id'))
|
||||||
|
->execute();
|
||||||
|
|
||||||
/** @var \Modules\Workflow\Models\WorkflowTemplate $template */
|
/** @var \Modules\Workflow\Models\WorkflowTemplate $template */
|
||||||
$template = WorkflowTemplateMapper::get()
|
$template = WorkflowTemplateMapper::get()
|
||||||
->with('source')
|
->with('source')
|
||||||
->with('source/sources')
|
->with('source/sources')
|
||||||
->where('template', (int) $request->getData('template'))
|
->where('id', $instance->template->getId())
|
||||||
|
->limit()
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
|
$view->addData('template', $template);
|
||||||
|
|
||||||
if (!(($template->source->findFile('instance-profile.tpl.php')) instanceof NullMedia)) {
|
if (!(($template->source->findFile('instance-profile.tpl.php')) instanceof NullMedia)) {
|
||||||
require_once $template->source->findFile('WorkflowController.php')->getPath();
|
require_once $template->source->findFile('WorkflowController.php')->getPath();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ namespace Modules\Workflow\Models;
|
||||||
* @link https://karaka.app
|
* @link https://karaka.app
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
final class NullWorkflowInstance extends WorkflowInstanceAbstract
|
final class NullWorkflowInstanceAbstract extends WorkflowInstanceAbstract
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
|
@ -31,13 +31,14 @@ interface WorkflowControllerInterface
|
||||||
/**
|
/**
|
||||||
* Create instance from request
|
* Create instance from request
|
||||||
*
|
*
|
||||||
* @param RequestAbstract $request Request
|
* @param RequestAbstract $request Request
|
||||||
|
* @param WorkflowTemplate $template Workflow template
|
||||||
*
|
*
|
||||||
* @return WorkflowInstanceAbstract
|
* @return WorkflowInstanceAbstract
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public function createInstanceFromRequest(RequestAbstract $request) : WorkflowInstanceAbstract;
|
public function createInstanceFromRequest(RequestAbstract $request, WorkflowTemplate $template) : WorkflowInstanceAbstract;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create list of all instances for this workflow from a request
|
* Create list of all instances for this workflow from a request
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ use Modules\Admin\Models\NullAccount;
|
||||||
* @link https://karaka.app
|
* @link https://karaka.app
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
abstract class WorkflowInstanceAbstract
|
class WorkflowInstanceAbstract
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* ID.
|
* ID.
|
||||||
|
|
@ -43,6 +43,14 @@ abstract class WorkflowInstanceAbstract
|
||||||
*/
|
*/
|
||||||
public string $title = '';
|
public string $title = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance status.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
private int $status = WorkflowInstanceStatus::WORKING;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Template.
|
* Template.
|
||||||
*
|
*
|
||||||
|
|
@ -90,4 +98,30 @@ abstract class WorkflowInstanceAbstract
|
||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set status
|
||||||
|
*
|
||||||
|
* @param int $status Status
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function setStatus(int $status) : void
|
||||||
|
{
|
||||||
|
$this->status = $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get status
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function getStatus() : int
|
||||||
|
{
|
||||||
|
return $this->status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
|
||||||
* @link https://karaka.app
|
* @link https://karaka.app
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
final class WorkflowInstanceMapper extends DataMapperFactory
|
final class WorkflowInstanceAbstractMapper extends DataMapperFactory
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Columns.
|
* Columns.
|
||||||
|
|
@ -35,6 +35,8 @@ final class WorkflowInstanceMapper extends DataMapperFactory
|
||||||
*/
|
*/
|
||||||
public const COLUMNS = [
|
public const COLUMNS = [
|
||||||
'workflow_instance_id' => ['name' => 'workflow_instance_id', 'type' => 'int', 'internal' => 'id'],
|
'workflow_instance_id' => ['name' => 'workflow_instance_id', 'type' => 'int', 'internal' => 'id'],
|
||||||
|
'workflow_instance_title' => ['name' => 'workflow_instance_title', 'type' => 'string', 'internal' => 'title'],
|
||||||
|
'workflow_instance_status' => ['name' => 'workflow_instance_status', 'type' => 'int', 'internal' => 'status'],
|
||||||
'workflow_instance_template' => ['name' => 'workflow_instance_template', 'type' => 'int', 'internal' => 'template'],
|
'workflow_instance_template' => ['name' => 'workflow_instance_template', 'type' => 'int', 'internal' => 'template'],
|
||||||
'workflow_instance_created_at' => ['name' => 'workflow_instance_created_at', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt', 'readonly' => true],
|
'workflow_instance_created_at' => ['name' => 'workflow_instance_created_at', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt', 'readonly' => true],
|
||||||
'workflow_instance_created_by' => ['name' => 'workflow_instance_created_by', 'type' => 'int', 'internal' => 'createdBy', 'readonly' => true],
|
'workflow_instance_created_by' => ['name' => 'workflow_instance_created_by', 'type' => 'int', 'internal' => 'createdBy', 'readonly' => true],
|
||||||
36
Models/WorkflowInstanceStatus.php
Normal file
36
Models/WorkflowInstanceStatus.php
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Karaka
|
||||||
|
*
|
||||||
|
* PHP Version 8.1
|
||||||
|
*
|
||||||
|
* @package Modules\Workflow\Models
|
||||||
|
* @copyright Dennis Eichhorn
|
||||||
|
* @license OMS License 1.0
|
||||||
|
* @version 1.0.0
|
||||||
|
* @link https://karaka.app
|
||||||
|
*/
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Modules\Workflow\Models;
|
||||||
|
|
||||||
|
use phpOMS\Stdlib\Base\Enum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Workflow status enum.
|
||||||
|
*
|
||||||
|
* @package Modules\Workflow\Models
|
||||||
|
* @license OMS License 1.0
|
||||||
|
* @link https://karaka.app
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
abstract class WorkflowInstanceStatus extends Enum
|
||||||
|
{
|
||||||
|
public const WORKING = 1;
|
||||||
|
|
||||||
|
public const SUSPENDED = 2;
|
||||||
|
|
||||||
|
public const CANCELED = 3;
|
||||||
|
|
||||||
|
public const DONE = 4;
|
||||||
|
}
|
||||||
|
|
@ -12,5 +12,34 @@
|
||||||
*/
|
*/
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/** @var \phpOMS\Views\View $this */
|
/**
|
||||||
echo $this->getData('nav')->render();
|
* @var \phpOMS\Views\View $this
|
||||||
|
*/
|
||||||
|
$instances = $this->getData('instances') ?? [];
|
||||||
|
|
||||||
|
echo $this->getData('nav')->render(); ?>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<div class="portlet">
|
||||||
|
<div class="portlet-head"><?= $this->getHtml('instance'); ?><i class="fa fa-download floatRight download btn"></i></div>
|
||||||
|
<table class="default">
|
||||||
|
<thead>
|
||||||
|
<td><?= $this->getHtml('Status'); ?>
|
||||||
|
<td class="wf-100"><?= $this->getHtml('Title'); ?>
|
||||||
|
<tbody>
|
||||||
|
<?php
|
||||||
|
$c = 0;
|
||||||
|
foreach ($instances as $key => $instance) : ++$c;
|
||||||
|
$url = \phpOMS\Uri\UriFactory::build('{/prefix}admin/instance/single?{?}&id=' . $instance->getId());
|
||||||
|
?>
|
||||||
|
<tr data-href="<?= $url; ?>">
|
||||||
|
<td><a href="<?= $url; ?>"><?= $this->printHtml((string) $instance->getStatus()); ?></a>
|
||||||
|
<td><a href="<?= $url; ?>"><?= $this->printHtml($instance->title); ?></a>
|
||||||
|
<?php endforeach; if ($c == 0) : ?>
|
||||||
|
<tr><td colspan="6" class="empty"><?= $this->getHtml('Empty', '0', '0'); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -12,5 +12,34 @@
|
||||||
*/
|
*/
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/** @var \phpOMS\Views\View $this */
|
/**
|
||||||
echo $this->getData('nav')->render();
|
* @var \phpOMS\Views\View $this
|
||||||
|
*/
|
||||||
|
$instances = $this->getData('instances') ?? [];
|
||||||
|
|
||||||
|
echo $this->getData('nav')->render(); ?>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<div class="portlet">
|
||||||
|
<div class="portlet-head"><?= $this->getHtml('instance'); ?><i class="fa fa-download floatRight download btn"></i></div>
|
||||||
|
<table class="default">
|
||||||
|
<thead>
|
||||||
|
<td><?= $this->getHtml('Status'); ?>
|
||||||
|
<td class="wf-100"><?= $this->getHtml('Title'); ?>
|
||||||
|
<tbody>
|
||||||
|
<?php
|
||||||
|
$c = 0;
|
||||||
|
foreach ($instances as $key => $instance) : ++$c;
|
||||||
|
$url = \phpOMS\Uri\UriFactory::build('{/prefix}workflow/instance/profile?{?}&id=' . $instance->getId());
|
||||||
|
?>
|
||||||
|
<tr data-href="<?= $url; ?>">
|
||||||
|
<td><a href="<?= $url; ?>"><?= $this->printHtml((string) $instance->getStatus()); ?></a>
|
||||||
|
<td><a href="<?= $url; ?>"><?= $this->printHtml($instance->title); ?></a>
|
||||||
|
<?php endforeach; if ($c == 0) : ?>
|
||||||
|
<tr><td colspan="6" class="empty"><?= $this->getHtml('Empty', '0', '0'); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Loading…
Reference in New Issue
Block a user