Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 604550a500 | |||
| fe1410568b | |||
| 912f37f8b2 | |||
| 252ccdfa10 | |||
| d898de5bdc | |||
| dfb0e22912 | |||
| 199d3da05e | |||
| 9417bb60cb |
@@ -5,7 +5,7 @@
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: Gitea.Workflow
|
||||
# INGROUP: moko-platform.Automation
|
||||
# VERSION: 02.48.52
|
||||
# VERSION: 02.51.06
|
||||
# BRIEF: Auto-create feature branch when an issue is opened
|
||||
|
||||
name: "Universal: Issue Branch"
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
INGROUP: MokoSuiteClient.Documentation
|
||||
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
PATH: ./CHANGELOG.md
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
BRIEF: Version history using `Keep a Changelog`
|
||||
-->
|
||||
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
DEFGROUP: Joomla.Plugin
|
||||
INGROUP: MokoSuiteClient.Documentation
|
||||
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
PATH: ./CODE_OF_CONDUCT.md
|
||||
BRIEF: Reference + packaging repo for Moko Consulting Developer GPT Other Default
|
||||
-->
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
DEFGROUP: mokoconsulting-tech.MokoSuiteClientBrand
|
||||
INGROUP: MokoStandards.Governance
|
||||
REPO: https://github.com/mokoconsulting-tech/MokoSuiteClientBrand
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
PATH: /GOVERNANCE.md
|
||||
BRIEF: Project governance rules, roles, and decision process for MokoSuiteClientBrand
|
||||
-->
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
INGROUP: MokoSuiteClient.Documentation
|
||||
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
PATH: ./LICENSE.md
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
BRIEF: Project license (GPL-3.0-or-later)
|
||||
-->
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
DEFGROUP: Joomla.Plugin
|
||||
INGROUP: MokoSuiteClient
|
||||
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
PATH: /README.md
|
||||
BRIEF: MokoSuiteClient platform plugin for Joomla
|
||||
-->
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ DEFGROUP: [PROJECT_NAME]
|
||||
INGROUP: [PROJECT_NAME].Documentation
|
||||
REPO: [REPOSITORY_URL]
|
||||
PATH: /SECURITY.md
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
BRIEF: Security vulnerability reporting and handling policy
|
||||
-->
|
||||
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
INGROUP: MokoSuiteClient.Build
|
||||
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
FILE: build-guide.md
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
PATH: /docs/guides/
|
||||
BRIEF: Build and packaging guide for the MokoSuiteClient system plugin
|
||||
NOTE: Defines environment setup, repository layout, packaging rules, and release preparation
|
||||
-->
|
||||
|
||||
# MokoSuiteClient Build Guide (VERSION: 02.48.52)
|
||||
# MokoSuiteClient Build Guide (VERSION: 02.51.06)
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
DEFGROUP: Joomla.Plugin
|
||||
INGROUP: MokoSuiteClient.Guides
|
||||
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
PATH: /docs/guides/configuration-guide.md
|
||||
BRIEF: Configuration guide for the MokoSuiteClient system plugin
|
||||
NOTE: Defines plugin parameters, expected behaviors, and recommended defaults
|
||||
-->
|
||||
|
||||
# MokoSuiteClient Configuration Guide (VERSION: 02.48.52)
|
||||
# MokoSuiteClient Configuration Guide (VERSION: 02.51.06)
|
||||
|
||||
## 1. Objective
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
DEFGROUP: Joomla.Plugin
|
||||
INGROUP: MokoSuiteClient.Guides
|
||||
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
PATH: /docs/guides/installation-guide.md
|
||||
BRIEF: Installation guide for the MokoSuiteClient system plugin
|
||||
NOTE: First document in the guide set
|
||||
-->
|
||||
|
||||
# MokoSuiteClient Installation Guide (VERSION: 02.48.52)
|
||||
# MokoSuiteClient Installation Guide (VERSION: 02.51.06)
|
||||
|
||||
## Introduction
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
DEFGROUP: Joomla.Plugin
|
||||
INGROUP: MokoSuiteClient.Guides
|
||||
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
PATH: /docs/guides/operations-guide.md
|
||||
BRIEF: Operational guide for administering and managing the MokoSuiteClient system plugin
|
||||
NOTE: Defines lifecycle, responsibilities, and operational behaviors
|
||||
-->
|
||||
|
||||
# MokoSuiteClient Operations Guide (VERSION: 02.48.52)
|
||||
# MokoSuiteClient Operations Guide (VERSION: 02.51.06)
|
||||
|
||||
## Introduction
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
DEFGROUP: Joomla.Plugin
|
||||
INGROUP: MokoSuiteClient.Guides
|
||||
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
PATH: /docs/guides/rollback-and-recovery-guide.md
|
||||
BRIEF: Rollback and recovery guide for restoring stable operation after plugin related incidents
|
||||
NOTE: Completes the core guide set for Suite plugin governance
|
||||
-->
|
||||
|
||||
# MokoSuiteClient Rollback and Recovery Guide (VERSION: 02.48.52)
|
||||
# MokoSuiteClient Rollback and Recovery Guide (VERSION: 02.51.06)
|
||||
|
||||
## Introduction
|
||||
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
DEFGROUP: Joomla.Plugin
|
||||
INGROUP: MokoSuiteClient.Guides
|
||||
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
PATH: /docs/guides/testing-guide.md
|
||||
BRIEF: Testing guide for MokoSuiteClient v02.01.08
|
||||
NOTE: Covers manual test procedures for language overrides, install/uninstall, and configuration
|
||||
-->
|
||||
|
||||
# MokoSuiteClient Testing Guide (VERSION: 02.48.52)
|
||||
# MokoSuiteClient Testing Guide (VERSION: 02.51.06)
|
||||
|
||||
## 1. Prerequisites
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
DEFGROUP: Joomla.Plugin
|
||||
INGROUP: MokoSuiteClient.Guides
|
||||
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
PATH: /docs/guides/troubleshooting-guide.md
|
||||
BRIEF: Troubleshooting guide for diagnosing and resolving issues related to the MokoSuiteClient plugin
|
||||
NOTE: Designed for administrators and Suite operations teams
|
||||
-->
|
||||
|
||||
# MokoSuiteClient Troubleshooting Guide (VERSION: 02.48.52)
|
||||
# MokoSuiteClient Troubleshooting Guide (VERSION: 02.51.06)
|
||||
|
||||
## Introduction
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
DEFGROUP: Joomla.Plugin
|
||||
INGROUP: MokoSuiteClient.Guides
|
||||
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
PATH: /docs/guides/upgrade-and-versioning-guide.md
|
||||
BRIEF: Guide for updating, versioning, and maintaining the MokoSuiteClient plugin
|
||||
NOTE: Defines release flow, version rules, and upgrade validation
|
||||
-->
|
||||
|
||||
# MokoSuiteClient Upgrade and Versioning Guide (VERSION: 02.48.52)
|
||||
# MokoSuiteClient Upgrade and Versioning Guide (VERSION: 02.51.06)
|
||||
|
||||
## Introduction
|
||||
|
||||
|
||||
+2
-2
@@ -10,13 +10,13 @@
|
||||
DEFGROUP: Joomla.Plugin
|
||||
INGROUP: MokoSuiteClient.Documentation
|
||||
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
PATH: /docs/index.md
|
||||
BRIEF: Master index of all documentation for the MokoSuiteClient plugin
|
||||
NOTE: Automatically maintained index for all guide canvases
|
||||
-->
|
||||
|
||||
# MokoSuiteClient Documentation Index (VERSION: 02.48.52)
|
||||
# MokoSuiteClient Documentation Index (VERSION: 02.51.06)
|
||||
|
||||
## Introduction
|
||||
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
INGROUP: MokoSuiteClient
|
||||
REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
PATH: /docs/plugin-basic.md
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
BRIEF: Baseline documentation for the MokoSuiteClient system plugin
|
||||
NOTE: Foundational reference for internal and external stakeholders
|
||||
-->
|
||||
|
||||
# MokoSuiteClient Plugin Overview (VERSION: 02.48.52)
|
||||
# MokoSuiteClient Plugin Overview (VERSION: 02.51.06)
|
||||
|
||||
## Introduction
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ DEFGROUP: MokoSuiteClient.Documentation
|
||||
INGROUP: MokoStandards.Templates
|
||||
REPO: https://github.com/mokoconsulting-tech/MokoSuiteClient
|
||||
PATH: /docs/update-server.md
|
||||
VERSION: 02.48.52
|
||||
VERSION: 02.51.06
|
||||
BRIEF: How this extension's Joomla update server file (update.xml) is managed
|
||||
-->
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ class DisplayController extends BaseController
|
||||
'templates' => 'mokosuiteclient.templates.manage',
|
||||
'replacements' => 'mokosuiteclient.replacements.manage',
|
||||
'conditions' => 'mokosuiteclient.conditions.manage',
|
||||
'modules' => 'core.admin',
|
||||
];
|
||||
|
||||
public function display($cachable = false, $urlparams = [])
|
||||
@@ -85,7 +86,12 @@ class DisplayController extends BaseController
|
||||
|
||||
public function sendHeartbeat()
|
||||
{
|
||||
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
||||
if (!Session::checkToken())
|
||||
{
|
||||
$this->jsonResponse(['success' => false, 'message' => 'Session expired — please reload the page.']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@@ -800,6 +806,61 @@ class DisplayController extends BaseController
|
||||
$this->jsonResponse($this->getModel('Import')->importAdminTools());
|
||||
}
|
||||
|
||||
// ==================================================================
|
||||
// Toggle Published
|
||||
// ==================================================================
|
||||
|
||||
public function togglePublished()
|
||||
{
|
||||
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
||||
|
||||
if (!$this->checkAcl('core.admin'))
|
||||
{
|
||||
$this->jsonForbidden();
|
||||
return;
|
||||
}
|
||||
|
||||
$app = Factory::getApplication();
|
||||
$table = $app->getInput()->getString('table', '');
|
||||
$id = $app->getInput()->getInt('id', 0);
|
||||
|
||||
$allowed = ['mokosuiteclient_conditions', 'mokosuiteclient_snippets',
|
||||
'mokosuiteclient_replacements', 'mokosuiteclient_content_templates', 'modules'];
|
||||
|
||||
if (!in_array($table, $allowed, true) || $id <= 0)
|
||||
{
|
||||
$this->jsonResponse(['success' => false, 'message' => 'Invalid table or ID.']);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$db = Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class);
|
||||
$dbTable = '#__' . $table;
|
||||
$current = (int) $db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->select($db->quoteName('published'))
|
||||
->from($db->quoteName($dbTable))
|
||||
->where($db->quoteName('id') . ' = ' . $id)
|
||||
)->loadResult();
|
||||
|
||||
$newState = $current ? 0 : 1;
|
||||
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->update($db->quoteName($dbTable))
|
||||
->set($db->quoteName('published') . ' = ' . $newState)
|
||||
->where($db->quoteName('id') . ' = ' . $id)
|
||||
)->execute();
|
||||
|
||||
$this->jsonResponse(['success' => true, 'published' => $newState]);
|
||||
}
|
||||
catch (\Throwable $e)
|
||||
{
|
||||
$this->jsonResponse(['success' => false, 'message' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================================================================
|
||||
// Helpers
|
||||
// ==================================================================
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Moko\Component\MokoSuiteClient\Administrator\Model;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
|
||||
use Joomla\Database\DatabaseInterface;
|
||||
|
||||
class ConditionsModel extends BaseDatabaseModel
|
||||
{
|
||||
public function getItems(array $filters = [], int $limit = 50, int $offset = 0): array
|
||||
{
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
$query = $db->getQuery(true)
|
||||
->select([
|
||||
$db->quoteName('c.id'),
|
||||
$db->quoteName('c.alias'),
|
||||
$db->quoteName('c.name'),
|
||||
$db->quoteName('c.description'),
|
||||
$db->quoteName('c.category'),
|
||||
$db->quoteName('c.color'),
|
||||
$db->quoteName('c.match_all'),
|
||||
$db->quoteName('c.published'),
|
||||
])
|
||||
->from($db->quoteName('#__mokosuiteclient_conditions', 'c'));
|
||||
|
||||
if (!empty($filters['search']))
|
||||
{
|
||||
$search = $db->quote('%' . $db->escape($filters['search'], true) . '%');
|
||||
$query->where('(' . $db->quoteName('c.name') . ' LIKE ' . $search
|
||||
. ' OR ' . $db->quoteName('c.alias') . ' LIKE ' . $search . ')');
|
||||
}
|
||||
|
||||
if ($filters['published'] !== '' && $filters['published'] !== null)
|
||||
{
|
||||
$query->where($db->quoteName('c.published') . ' = ' . (int) $filters['published']);
|
||||
}
|
||||
|
||||
$query->order($db->quoteName('c.name') . ' ASC');
|
||||
$db->setQuery($query, $offset, $limit);
|
||||
|
||||
return $db->loadObjectList() ?: [];
|
||||
}
|
||||
|
||||
public function getTotal(array $filters = []): int
|
||||
{
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from($db->quoteName('#__mokosuiteclient_conditions', 'c'));
|
||||
|
||||
if (!empty($filters['search']))
|
||||
{
|
||||
$search = $db->quote('%' . $db->escape($filters['search'], true) . '%');
|
||||
$query->where('(' . $db->quoteName('c.name') . ' LIKE ' . $search
|
||||
. ' OR ' . $db->quoteName('c.alias') . ' LIKE ' . $search . ')');
|
||||
}
|
||||
|
||||
if ($filters['published'] !== '' && $filters['published'] !== null)
|
||||
{
|
||||
$query->where($db->quoteName('c.published') . ' = ' . (int) $filters['published']);
|
||||
}
|
||||
|
||||
$db->setQuery($query);
|
||||
|
||||
return (int) $db->loadResult();
|
||||
}
|
||||
|
||||
public function getGroupCount(int $conditionId): int
|
||||
{
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from($db->quoteName('#__mokosuiteclient_conditions_groups'))
|
||||
->where($db->quoteName('condition_id') . ' = ' . $conditionId)
|
||||
);
|
||||
|
||||
return (int) $db->loadResult();
|
||||
}
|
||||
|
||||
public function getRuleCount(int $conditionId): int
|
||||
{
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from($db->quoteName('#__mokosuiteclient_conditions_rules', 'r'))
|
||||
->join('INNER', $db->quoteName('#__mokosuiteclient_conditions_groups', 'g')
|
||||
. ' ON ' . $db->quoteName('g.id') . ' = ' . $db->quoteName('r.group_id'))
|
||||
->where($db->quoteName('g.condition_id') . ' = ' . $conditionId)
|
||||
);
|
||||
|
||||
return (int) $db->loadResult();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Moko\Component\MokoSuiteClient\Administrator\Model;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
|
||||
use Joomla\Database\DatabaseInterface;
|
||||
|
||||
class ModulesModel extends BaseDatabaseModel
|
||||
{
|
||||
public function getItems(array $filters = [], int $limit = 50, int $offset = 0): array
|
||||
{
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
$query = $db->getQuery(true)
|
||||
->select([
|
||||
$db->quoteName('m.id'),
|
||||
$db->quoteName('m.title'),
|
||||
$db->quoteName('m.module'),
|
||||
$db->quoteName('m.position'),
|
||||
$db->quoteName('m.published'),
|
||||
$db->quoteName('m.ordering'),
|
||||
$db->quoteName('m.client_id'),
|
||||
$db->quoteName('m.access'),
|
||||
$db->quoteName('m.language'),
|
||||
])
|
||||
->from($db->quoteName('#__modules', 'm'));
|
||||
|
||||
if (!empty($filters['search']))
|
||||
{
|
||||
$search = $db->quote('%' . $db->escape($filters['search'], true) . '%');
|
||||
$query->where('(' . $db->quoteName('m.title') . ' LIKE ' . $search
|
||||
. ' OR ' . $db->quoteName('m.module') . ' LIKE ' . $search
|
||||
. ' OR ' . $db->quoteName('m.position') . ' LIKE ' . $search . ')');
|
||||
}
|
||||
|
||||
if ($filters['published'] !== '' && $filters['published'] !== null)
|
||||
{
|
||||
$query->where($db->quoteName('m.published') . ' = ' . (int) $filters['published']);
|
||||
}
|
||||
|
||||
if ($filters['client_id'] !== '' && $filters['client_id'] !== null)
|
||||
{
|
||||
$query->where($db->quoteName('m.client_id') . ' = ' . (int) $filters['client_id']);
|
||||
}
|
||||
|
||||
$query->order($db->quoteName('m.client_id') . ' ASC, '
|
||||
. $db->quoteName('m.position') . ' ASC, '
|
||||
. $db->quoteName('m.ordering') . ' ASC');
|
||||
$db->setQuery($query, $offset, $limit);
|
||||
|
||||
return $db->loadObjectList() ?: [];
|
||||
}
|
||||
|
||||
public function getTotal(array $filters = []): int
|
||||
{
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from($db->quoteName('#__modules', 'm'));
|
||||
|
||||
if (!empty($filters['search']))
|
||||
{
|
||||
$search = $db->quote('%' . $db->escape($filters['search'], true) . '%');
|
||||
$query->where('(' . $db->quoteName('m.title') . ' LIKE ' . $search
|
||||
. ' OR ' . $db->quoteName('m.module') . ' LIKE ' . $search
|
||||
. ' OR ' . $db->quoteName('m.position') . ' LIKE ' . $search . ')');
|
||||
}
|
||||
|
||||
if ($filters['published'] !== '' && $filters['published'] !== null)
|
||||
{
|
||||
$query->where($db->quoteName('m.published') . ' = ' . (int) $filters['published']);
|
||||
}
|
||||
|
||||
if ($filters['client_id'] !== '' && $filters['client_id'] !== null)
|
||||
{
|
||||
$query->where($db->quoteName('m.client_id') . ' = ' . (int) $filters['client_id']);
|
||||
}
|
||||
|
||||
$db->setQuery($query);
|
||||
|
||||
return (int) $db->loadResult();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Moko\Component\MokoSuiteClient\Administrator\Model;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
|
||||
use Joomla\Database\DatabaseInterface;
|
||||
|
||||
class ReplacementsModel extends BaseDatabaseModel
|
||||
{
|
||||
public function getItems(array $filters = [], int $limit = 50, int $offset = 0): array
|
||||
{
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
$query = $db->getQuery(true)
|
||||
->select('*')
|
||||
->from($db->quoteName('#__mokosuiteclient_replacements'));
|
||||
|
||||
if (!empty($filters['search']))
|
||||
{
|
||||
$search = $db->quote('%' . $db->escape($filters['search'], true) . '%');
|
||||
$query->where('(' . $db->quoteName('name') . ' LIKE ' . $search
|
||||
. ' OR ' . $db->quoteName('search') . ' LIKE ' . $search . ')');
|
||||
}
|
||||
|
||||
if ($filters['published'] !== '' && $filters['published'] !== null)
|
||||
{
|
||||
$query->where($db->quoteName('published') . ' = ' . (int) $filters['published']);
|
||||
}
|
||||
|
||||
$query->order($db->quoteName('ordering') . ' ASC, ' . $db->quoteName('name') . ' ASC');
|
||||
$db->setQuery($query, $offset, $limit);
|
||||
|
||||
return $db->loadObjectList() ?: [];
|
||||
}
|
||||
|
||||
public function getTotal(array $filters = []): int
|
||||
{
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from($db->quoteName('#__mokosuiteclient_replacements'));
|
||||
|
||||
if (!empty($filters['search']))
|
||||
{
|
||||
$search = $db->quote('%' . $db->escape($filters['search'], true) . '%');
|
||||
$query->where('(' . $db->quoteName('name') . ' LIKE ' . $search
|
||||
. ' OR ' . $db->quoteName('search') . ' LIKE ' . $search . ')');
|
||||
}
|
||||
|
||||
if ($filters['published'] !== '' && $filters['published'] !== null)
|
||||
{
|
||||
$query->where($db->quoteName('published') . ' = ' . (int) $filters['published']);
|
||||
}
|
||||
|
||||
$db->setQuery($query);
|
||||
|
||||
return (int) $db->loadResult();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Moko\Component\MokoSuiteClient\Administrator\Model;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
|
||||
use Joomla\Database\DatabaseInterface;
|
||||
|
||||
class SnippetsModel extends BaseDatabaseModel
|
||||
{
|
||||
public function getItems(array $filters = [], int $limit = 50, int $offset = 0): array
|
||||
{
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
$query = $db->getQuery(true)
|
||||
->select('*')
|
||||
->from($db->quoteName('#__mokosuiteclient_snippets'));
|
||||
|
||||
if (!empty($filters['search']))
|
||||
{
|
||||
$search = $db->quote('%' . $db->escape($filters['search'], true) . '%');
|
||||
$query->where('(' . $db->quoteName('name') . ' LIKE ' . $search
|
||||
. ' OR ' . $db->quoteName('alias') . ' LIKE ' . $search . ')');
|
||||
}
|
||||
|
||||
if ($filters['published'] !== '' && $filters['published'] !== null)
|
||||
{
|
||||
$query->where($db->quoteName('published') . ' = ' . (int) $filters['published']);
|
||||
}
|
||||
|
||||
$query->order($db->quoteName('ordering') . ' ASC, ' . $db->quoteName('name') . ' ASC');
|
||||
$db->setQuery($query, $offset, $limit);
|
||||
|
||||
return $db->loadObjectList() ?: [];
|
||||
}
|
||||
|
||||
public function getTotal(array $filters = []): int
|
||||
{
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from($db->quoteName('#__mokosuiteclient_snippets'));
|
||||
|
||||
if (!empty($filters['search']))
|
||||
{
|
||||
$search = $db->quote('%' . $db->escape($filters['search'], true) . '%');
|
||||
$query->where('(' . $db->quoteName('name') . ' LIKE ' . $search
|
||||
. ' OR ' . $db->quoteName('alias') . ' LIKE ' . $search . ')');
|
||||
}
|
||||
|
||||
if ($filters['published'] !== '' && $filters['published'] !== null)
|
||||
{
|
||||
$query->where($db->quoteName('published') . ' = ' . (int) $filters['published']);
|
||||
}
|
||||
|
||||
$db->setQuery($query);
|
||||
|
||||
return (int) $db->loadResult();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Moko\Component\MokoSuiteClient\Administrator\Model;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
|
||||
use Joomla\Database\DatabaseInterface;
|
||||
|
||||
class TemplatesModel extends BaseDatabaseModel
|
||||
{
|
||||
public function getItems(array $filters = [], int $limit = 50, int $offset = 0): array
|
||||
{
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
$query = $db->getQuery(true)
|
||||
->select('*')
|
||||
->from($db->quoteName('#__mokosuiteclient_content_templates'));
|
||||
|
||||
if (!empty($filters['search']))
|
||||
{
|
||||
$search = $db->quote('%' . $db->escape($filters['search'], true) . '%');
|
||||
$query->where('(' . $db->quoteName('name') . ' LIKE ' . $search
|
||||
. ' OR ' . $db->quoteName('alias') . ' LIKE ' . $search . ')');
|
||||
}
|
||||
|
||||
if ($filters['published'] !== '' && $filters['published'] !== null)
|
||||
{
|
||||
$query->where($db->quoteName('published') . ' = ' . (int) $filters['published']);
|
||||
}
|
||||
|
||||
$query->order($db->quoteName('ordering') . ' ASC, ' . $db->quoteName('name') . ' ASC');
|
||||
$db->setQuery($query, $offset, $limit);
|
||||
|
||||
return $db->loadObjectList() ?: [];
|
||||
}
|
||||
|
||||
public function getTotal(array $filters = []): int
|
||||
{
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from($db->quoteName('#__mokosuiteclient_content_templates'));
|
||||
|
||||
if (!empty($filters['search']))
|
||||
{
|
||||
$search = $db->quote('%' . $db->escape($filters['search'], true) . '%');
|
||||
$query->where('(' . $db->quoteName('name') . ' LIKE ' . $search
|
||||
. ' OR ' . $db->quoteName('alias') . ' LIKE ' . $search . ')');
|
||||
}
|
||||
|
||||
if ($filters['published'] !== '' && $filters['published'] !== null)
|
||||
{
|
||||
$query->where($db->quoteName('published') . ' = ' . (int) $filters['published']);
|
||||
}
|
||||
|
||||
$db->setQuery($query);
|
||||
|
||||
return (int) $db->loadResult();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Moko\Component\MokoSuiteClient\Administrator\View\Conditions;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
use Joomla\CMS\Toolbar\ToolbarHelper;
|
||||
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
protected $items = [];
|
||||
protected $total = 0;
|
||||
protected $filters = [];
|
||||
|
||||
public function display($tpl = null)
|
||||
{
|
||||
$model = new \Moko\Component\MokoSuiteClient\Administrator\Model\ConditionsModel();
|
||||
$input = Factory::getApplication()->getInput();
|
||||
|
||||
$this->filters = [
|
||||
'search' => $input->getString('filter_search', ''),
|
||||
'published' => $input->get('filter_published', ''),
|
||||
];
|
||||
|
||||
$page = max(1, $input->getInt('page', 1));
|
||||
$limit = 50;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
$this->items = $model->getItems($this->filters, $limit, $offset);
|
||||
$this->total = $model->getTotal($this->filters);
|
||||
|
||||
foreach ($this->items as $item)
|
||||
{
|
||||
$item->group_count = $model->getGroupCount((int) $item->id);
|
||||
$item->rule_count = $model->getRuleCount((int) $item->id);
|
||||
}
|
||||
|
||||
$this->addToolbar();
|
||||
|
||||
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
|
||||
$wa->registerAndUseStyle('com_mokosuiteclient.dashboard', 'com_mokosuiteclient/dashboard.css');
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
|
||||
protected function addToolbar(): void
|
||||
{
|
||||
ToolbarHelper::title('Conditions', 'shuffle');
|
||||
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Moko\Component\MokoSuiteClient\Administrator\View\Modules;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
use Joomla\CMS\Toolbar\ToolbarHelper;
|
||||
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
protected $items = [];
|
||||
protected $total = 0;
|
||||
protected $filters = [];
|
||||
|
||||
public function display($tpl = null)
|
||||
{
|
||||
$model = new \Moko\Component\MokoSuiteClient\Administrator\Model\ModulesModel();
|
||||
$input = Factory::getApplication()->getInput();
|
||||
|
||||
$this->filters = [
|
||||
'search' => $input->getString('filter_search', ''),
|
||||
'published' => $input->get('filter_published', ''),
|
||||
'client_id' => $input->get('filter_client', ''),
|
||||
];
|
||||
|
||||
$page = max(1, $input->getInt('page', 1));
|
||||
$limit = 50;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
$this->items = $model->getItems($this->filters, $limit, $offset);
|
||||
$this->total = $model->getTotal($this->filters);
|
||||
|
||||
$this->addToolbar();
|
||||
|
||||
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
|
||||
$wa->registerAndUseStyle('com_mokosuiteclient.dashboard', 'com_mokosuiteclient/dashboard.css');
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
|
||||
protected function addToolbar(): void
|
||||
{
|
||||
ToolbarHelper::title('Module Manager', 'cube');
|
||||
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Moko\Component\MokoSuiteClient\Administrator\View\Replacements;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
use Joomla\CMS\Toolbar\ToolbarHelper;
|
||||
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
protected $items = [];
|
||||
protected $total = 0;
|
||||
protected $filters = [];
|
||||
|
||||
public function display($tpl = null)
|
||||
{
|
||||
$model = new \Moko\Component\MokoSuiteClient\Administrator\Model\ReplacementsModel();
|
||||
$input = Factory::getApplication()->getInput();
|
||||
|
||||
$this->filters = [
|
||||
'search' => $input->getString('filter_search', ''),
|
||||
'published' => $input->get('filter_published', ''),
|
||||
];
|
||||
|
||||
$page = max(1, $input->getInt('page', 1));
|
||||
$limit = 50;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
$this->items = $model->getItems($this->filters, $limit, $offset);
|
||||
$this->total = $model->getTotal($this->filters);
|
||||
|
||||
$this->addToolbar();
|
||||
|
||||
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
|
||||
$wa->registerAndUseStyle('com_mokosuiteclient.dashboard', 'com_mokosuiteclient/dashboard.css');
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
|
||||
protected function addToolbar(): void
|
||||
{
|
||||
ToolbarHelper::title('Replacements', 'right-left');
|
||||
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Moko\Component\MokoSuiteClient\Administrator\View\Snippets;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
use Joomla\CMS\Toolbar\ToolbarHelper;
|
||||
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
protected $items = [];
|
||||
protected $total = 0;
|
||||
protected $filters = [];
|
||||
|
||||
public function display($tpl = null)
|
||||
{
|
||||
$model = new \Moko\Component\MokoSuiteClient\Administrator\Model\SnippetsModel();
|
||||
$input = Factory::getApplication()->getInput();
|
||||
|
||||
$this->filters = [
|
||||
'search' => $input->getString('filter_search', ''),
|
||||
'published' => $input->get('filter_published', ''),
|
||||
];
|
||||
|
||||
$page = max(1, $input->getInt('page', 1));
|
||||
$limit = 50;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
$this->items = $model->getItems($this->filters, $limit, $offset);
|
||||
$this->total = $model->getTotal($this->filters);
|
||||
|
||||
$this->addToolbar();
|
||||
|
||||
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
|
||||
$wa->registerAndUseStyle('com_mokosuiteclient.dashboard', 'com_mokosuiteclient/dashboard.css');
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
|
||||
protected function addToolbar(): void
|
||||
{
|
||||
ToolbarHelper::title('Snippets', 'code');
|
||||
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Moko\Component\MokoSuiteClient\Administrator\View\Templates;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
use Joomla\CMS\Toolbar\ToolbarHelper;
|
||||
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
protected $items = [];
|
||||
protected $total = 0;
|
||||
protected $filters = [];
|
||||
|
||||
public function display($tpl = null)
|
||||
{
|
||||
$model = new \Moko\Component\MokoSuiteClient\Administrator\Model\TemplatesModel();
|
||||
$input = Factory::getApplication()->getInput();
|
||||
|
||||
$this->filters = [
|
||||
'search' => $input->getString('filter_search', ''),
|
||||
'published' => $input->get('filter_published', ''),
|
||||
];
|
||||
|
||||
$page = max(1, $input->getInt('page', 1));
|
||||
$limit = 50;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
$this->items = $model->getItems($this->filters, $limit, $offset);
|
||||
$this->total = $model->getTotal($this->filters);
|
||||
|
||||
$this->addToolbar();
|
||||
|
||||
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
|
||||
$wa->registerAndUseStyle('com_mokosuiteclient.dashboard', 'com_mokosuiteclient/dashboard.css');
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
|
||||
protected function addToolbar(): void
|
||||
{
|
||||
ToolbarHelper::title('Content Templates', 'file-lines');
|
||||
ToolbarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mokosuiteclient');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Session\Session;
|
||||
|
||||
$items = $this->items;
|
||||
$total = $this->total;
|
||||
$filters = $this->filters;
|
||||
$token = Session::getFormToken();
|
||||
$input = Factory::getApplication()->getInput();
|
||||
$page = max(1, $input->getInt('page', 1));
|
||||
$pages = max(1, ceil($total / 50));
|
||||
?>
|
||||
|
||||
<div id="mokosuiteclient-conditions">
|
||||
<form method="get" action="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=conditions'); ?>" class="mb-3">
|
||||
<input type="hidden" name="option" value="com_mokosuiteclient">
|
||||
<input type="hidden" name="view" value="conditions">
|
||||
<div class="row g-2 align-items-end">
|
||||
<div class="col-md-4">
|
||||
<input type="text" name="filter_search" class="form-control form-control-sm" placeholder="Search by name or alias..." value="<?php echo htmlspecialchars($filters['search'], ENT_QUOTES, 'UTF-8'); ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select name="filter_published" class="form-select form-select-sm">
|
||||
<option value="">All States</option>
|
||||
<option value="1"<?php echo $filters['published'] === '1' ? ' selected' : ''; ?>>Published</option>
|
||||
<option value="0"<?php echo $filters['published'] === '0' ? ' selected' : ''; ?>>Unpublished</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-sm btn-primary"><span class="icon-search"></span> Filter</button>
|
||||
<a href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=conditions'); ?>" class="btn btn-sm btn-outline-secondary">Reset</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span><span class="icon-shuffle"></span> Conditions</span>
|
||||
<span class="badge bg-secondary"><?php echo number_format($total); ?> total</span>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:5%">ID</th>
|
||||
<th>Name</th>
|
||||
<th>Alias</th>
|
||||
<th>Category</th>
|
||||
<th style="width:8%">Match</th>
|
||||
<th style="width:8%">Groups</th>
|
||||
<th style="width:8%">Rules</th>
|
||||
<th style="width:8%">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($items)): ?>
|
||||
<tr><td colspan="8" class="text-center text-muted py-4">No conditions found.</td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($items as $item): ?>
|
||||
<tr>
|
||||
<td><?php echo (int) $item->id; ?></td>
|
||||
<td>
|
||||
<?php if ($item->color): ?>
|
||||
<span style="display:inline-block;width:12px;height:12px;border-radius:2px;background:<?php echo htmlspecialchars($item->color, ENT_QUOTES, 'UTF-8'); ?>;vertical-align:middle;margin-right:4px;"></span>
|
||||
<?php endif; ?>
|
||||
<?php echo htmlspecialchars($item->name, ENT_QUOTES, 'UTF-8'); ?>
|
||||
</td>
|
||||
<td><code><?php echo htmlspecialchars($item->alias, ENT_QUOTES, 'UTF-8'); ?></code></td>
|
||||
<td>
|
||||
<?php if ($item->category): ?>
|
||||
<span class="badge bg-info"><?php echo htmlspecialchars($item->category, ENT_QUOTES, 'UTF-8'); ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><span class="badge bg-<?php echo $item->match_all ? 'primary' : 'warning text-dark'; ?>"><?php echo $item->match_all ? 'ALL' : 'ANY'; ?></span></td>
|
||||
<td><?php echo (int) $item->group_count; ?></td>
|
||||
<td><?php echo (int) $item->rule_count; ?></td>
|
||||
<td>
|
||||
<a href="#" class="mokosuite-toggle-published badge bg-<?php echo $item->published ? 'success' : 'danger'; ?>"
|
||||
data-table="mokosuiteclient_conditions" data-id="<?php echo (int) $item->id; ?>"
|
||||
data-token="<?php echo $token; ?>">
|
||||
<?php echo $item->published ? 'Published' : 'Unpublished'; ?>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($pages > 1): ?>
|
||||
<nav class="mt-3"><ul class="pagination pagination-sm justify-content-center">
|
||||
<?php for ($p = 1; $p <= $pages; $p++): ?>
|
||||
<li class="page-item<?php echo $p === $page ? ' active' : ''; ?>">
|
||||
<a class="page-link" href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=conditions&page=' . $p
|
||||
. ($filters['search'] ? '&filter_search=' . urlencode($filters['search']) : '')
|
||||
. ($filters['published'] !== '' ? '&filter_published=' . $filters['published'] : '')); ?>"><?php echo $p; ?></a>
|
||||
</li>
|
||||
<?php endfor; ?>
|
||||
</ul></nav>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('.mokosuite-toggle-published').forEach(function(el) {
|
||||
el.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
var table = this.dataset.table, id = this.dataset.id, token = this.dataset.token, badge = this;
|
||||
var fd = new FormData();
|
||||
fd.append('table', table);
|
||||
fd.append('id', id);
|
||||
fd.append(token, '1');
|
||||
fetch('index.php?option=com_mokosuiteclient&task=display.togglePublished&format=json', {
|
||||
method: 'POST', headers: {'X-Requested-With': 'XMLHttpRequest'}, body: fd
|
||||
}).then(function(r) { return r.json(); }).then(function(d) {
|
||||
if (d.success) {
|
||||
var pub = d.published;
|
||||
badge.className = 'mokosuite-toggle-published badge bg-' + (pub ? 'success' : 'danger');
|
||||
badge.textContent = pub ? 'Published' : 'Unpublished';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Session\Session;
|
||||
|
||||
$items = $this->items;
|
||||
$total = $this->total;
|
||||
$filters = $this->filters;
|
||||
$token = Session::getFormToken();
|
||||
$input = Factory::getApplication()->getInput();
|
||||
$page = max(1, $input->getInt('page', 1));
|
||||
$pages = max(1, ceil($total / 50));
|
||||
|
||||
$publishedLabels = [1 => 'Published', 0 => 'Unpublished', -2 => 'Trashed'];
|
||||
$publishedColors = [1 => 'success', 0 => 'danger', -2 => 'dark'];
|
||||
?>
|
||||
|
||||
<div id="mokosuiteclient-modules">
|
||||
<form method="get" action="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=modules'); ?>" class="mb-3">
|
||||
<input type="hidden" name="option" value="com_mokosuiteclient">
|
||||
<input type="hidden" name="view" value="modules">
|
||||
<div class="row g-2 align-items-end">
|
||||
<div class="col-md-3">
|
||||
<input type="text" name="filter_search" class="form-control form-control-sm" placeholder="Search title, type, or position..." value="<?php echo htmlspecialchars($filters['search'], ENT_QUOTES, 'UTF-8'); ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select name="filter_client" class="form-select form-select-sm">
|
||||
<option value="">All Clients</option>
|
||||
<option value="0"<?php echo $filters['client_id'] === '0' ? ' selected' : ''; ?>>Site</option>
|
||||
<option value="1"<?php echo $filters['client_id'] === '1' ? ' selected' : ''; ?>>Administrator</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select name="filter_published" class="form-select form-select-sm">
|
||||
<option value="">All States</option>
|
||||
<option value="1"<?php echo $filters['published'] === '1' ? ' selected' : ''; ?>>Published</option>
|
||||
<option value="0"<?php echo $filters['published'] === '0' ? ' selected' : ''; ?>>Unpublished</option>
|
||||
<option value="-2"<?php echo $filters['published'] === '-2' ? ' selected' : ''; ?>>Trashed</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-sm btn-primary"><span class="icon-search"></span> Filter</button>
|
||||
<a href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=modules'); ?>" class="btn btn-sm btn-outline-secondary">Reset</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span><span class="icon-cube"></span> Module Manager</span>
|
||||
<span class="badge bg-secondary"><?php echo number_format($total); ?> total</span>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:5%">ID</th>
|
||||
<th>Title</th>
|
||||
<th>Position</th>
|
||||
<th>Type</th>
|
||||
<th style="width:8%">Client</th>
|
||||
<th style="width:8%">Order</th>
|
||||
<th style="width:8%">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($items)): ?>
|
||||
<tr><td colspan="7" class="text-center text-muted py-4">No modules found.</td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($items as $item): ?>
|
||||
<tr>
|
||||
<td><?php echo (int) $item->id; ?></td>
|
||||
<td>
|
||||
<a href="<?php echo Route::_('index.php?option=com_modules&task=module.edit&id=' . (int) $item->id); ?>">
|
||||
<?php echo htmlspecialchars($item->title, ENT_QUOTES, 'UTF-8'); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td><code><?php echo htmlspecialchars($item->position ?: '(none)', ENT_QUOTES, 'UTF-8'); ?></code></td>
|
||||
<td><small><?php echo htmlspecialchars($item->module, ENT_QUOTES, 'UTF-8'); ?></small></td>
|
||||
<td><span class="badge bg-<?php echo $item->client_id ? 'dark' : 'primary'; ?>"><?php echo $item->client_id ? 'Admin' : 'Site'; ?></span></td>
|
||||
<td><?php echo (int) $item->ordering; ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$pub = (int) $item->published;
|
||||
$label = $publishedLabels[$pub] ?? 'Unknown';
|
||||
$color = $publishedColors[$pub] ?? 'secondary';
|
||||
?>
|
||||
<a href="#" class="mokosuite-toggle-module badge bg-<?php echo $color; ?>"
|
||||
data-id="<?php echo (int) $item->id; ?>"
|
||||
data-token="<?php echo $token; ?>">
|
||||
<?php echo $label; ?>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($pages > 1): ?>
|
||||
<nav class="mt-3"><ul class="pagination pagination-sm justify-content-center">
|
||||
<?php for ($p = 1; $p <= $pages; $p++): ?>
|
||||
<li class="page-item<?php echo $p === $page ? ' active' : ''; ?>">
|
||||
<a class="page-link" href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=modules&page=' . $p
|
||||
. ($filters['search'] ? '&filter_search=' . urlencode($filters['search']) : '')
|
||||
. ($filters['published'] !== '' ? '&filter_published=' . $filters['published'] : '')
|
||||
. ($filters['client_id'] !== '' ? '&filter_client=' . $filters['client_id'] : '')); ?>"><?php echo $p; ?></a>
|
||||
</li>
|
||||
<?php endfor; ?>
|
||||
</ul></nav>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('.mokosuite-toggle-module').forEach(function(el) {
|
||||
el.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
var id = this.dataset.id, token = this.dataset.token, badge = this;
|
||||
var fd = new FormData();
|
||||
fd.append('table', 'modules');
|
||||
fd.append('id', id);
|
||||
fd.append(token, '1');
|
||||
fetch('index.php?option=com_mokosuiteclient&task=display.togglePublished&format=json', {
|
||||
method: 'POST', headers: {'X-Requested-With': 'XMLHttpRequest'}, body: fd
|
||||
}).then(function(r) { return r.json(); }).then(function(d) {
|
||||
if (d.success) {
|
||||
var pub = d.published;
|
||||
badge.className = 'mokosuite-toggle-module badge bg-' + (pub ? 'success' : 'danger');
|
||||
badge.textContent = pub ? 'Published' : 'Unpublished';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Session\Session;
|
||||
|
||||
$items = $this->items;
|
||||
$total = $this->total;
|
||||
$filters = $this->filters;
|
||||
$token = Session::getFormToken();
|
||||
$input = Factory::getApplication()->getInput();
|
||||
$page = max(1, $input->getInt('page', 1));
|
||||
$pages = max(1, ceil($total / 50));
|
||||
?>
|
||||
|
||||
<div id="mokosuiteclient-replacements">
|
||||
<form method="get" action="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=replacements'); ?>" class="mb-3">
|
||||
<input type="hidden" name="option" value="com_mokosuiteclient">
|
||||
<input type="hidden" name="view" value="replacements">
|
||||
<div class="row g-2 align-items-end">
|
||||
<div class="col-md-4">
|
||||
<input type="text" name="filter_search" class="form-control form-control-sm" placeholder="Search by name or pattern..." value="<?php echo htmlspecialchars($filters['search'], ENT_QUOTES, 'UTF-8'); ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select name="filter_published" class="form-select form-select-sm">
|
||||
<option value="">All States</option>
|
||||
<option value="1"<?php echo $filters['published'] === '1' ? ' selected' : ''; ?>>Published</option>
|
||||
<option value="0"<?php echo $filters['published'] === '0' ? ' selected' : ''; ?>>Unpublished</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-sm btn-primary"><span class="icon-search"></span> Filter</button>
|
||||
<a href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=replacements'); ?>" class="btn btn-sm btn-outline-secondary">Reset</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span><span class="icon-right-left"></span> Replacements</span>
|
||||
<span class="badge bg-secondary"><?php echo number_format($total); ?> total</span>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:5%">ID</th>
|
||||
<th>Name</th>
|
||||
<th>Search</th>
|
||||
<th>Replace</th>
|
||||
<th style="width:7%">Area</th>
|
||||
<th style="width:5%">Regex</th>
|
||||
<th>Category</th>
|
||||
<th style="width:8%">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($items)): ?>
|
||||
<tr><td colspan="8" class="text-center text-muted py-4">No replacement rules found.</td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($items as $item): ?>
|
||||
<tr>
|
||||
<td><?php echo (int) $item->id; ?></td>
|
||||
<td>
|
||||
<?php if ($item->color): ?>
|
||||
<span style="display:inline-block;width:12px;height:12px;border-radius:2px;background:<?php echo htmlspecialchars($item->color, ENT_QUOTES, 'UTF-8'); ?>;vertical-align:middle;margin-right:4px;"></span>
|
||||
<?php endif; ?>
|
||||
<?php echo htmlspecialchars($item->name, ENT_QUOTES, 'UTF-8'); ?>
|
||||
</td>
|
||||
<td><code style="font-size:0.8rem"><?php echo htmlspecialchars(mb_strimwidth($item->search, 0, 50, '...'), ENT_QUOTES, 'UTF-8'); ?></code></td>
|
||||
<td><code style="font-size:0.8rem"><?php echo htmlspecialchars(mb_strimwidth($item->replace_value, 0, 50, '...'), ENT_QUOTES, 'UTF-8'); ?></code></td>
|
||||
<td><span class="badge bg-secondary"><?php echo htmlspecialchars($item->area, ENT_QUOTES, 'UTF-8'); ?></span></td>
|
||||
<td><?php echo $item->regex ? '<span class="badge bg-warning text-dark">Yes</span>' : ''; ?></td>
|
||||
<td>
|
||||
<?php if ($item->category): ?>
|
||||
<span class="badge bg-info"><?php echo htmlspecialchars($item->category, ENT_QUOTES, 'UTF-8'); ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" class="mokosuite-toggle-published badge bg-<?php echo $item->published ? 'success' : 'danger'; ?>"
|
||||
data-table="mokosuiteclient_replacements" data-id="<?php echo (int) $item->id; ?>"
|
||||
data-token="<?php echo $token; ?>">
|
||||
<?php echo $item->published ? 'Published' : 'Unpublished'; ?>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($pages > 1): ?>
|
||||
<nav class="mt-3"><ul class="pagination pagination-sm justify-content-center">
|
||||
<?php for ($p = 1; $p <= $pages; $p++): ?>
|
||||
<li class="page-item<?php echo $p === $page ? ' active' : ''; ?>">
|
||||
<a class="page-link" href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=replacements&page=' . $p
|
||||
. ($filters['search'] ? '&filter_search=' . urlencode($filters['search']) : '')
|
||||
. ($filters['published'] !== '' ? '&filter_published=' . $filters['published'] : '')); ?>"><?php echo $p; ?></a>
|
||||
</li>
|
||||
<?php endfor; ?>
|
||||
</ul></nav>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('.mokosuite-toggle-published').forEach(function(el) {
|
||||
el.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
var table = this.dataset.table, id = this.dataset.id, token = this.dataset.token, badge = this;
|
||||
var fd = new FormData();
|
||||
fd.append('table', table);
|
||||
fd.append('id', id);
|
||||
fd.append(token, '1');
|
||||
fetch('index.php?option=com_mokosuiteclient&task=display.togglePublished&format=json', {
|
||||
method: 'POST', headers: {'X-Requested-With': 'XMLHttpRequest'}, body: fd
|
||||
}).then(function(r) { return r.json(); }).then(function(d) {
|
||||
if (d.success) {
|
||||
var pub = d.published;
|
||||
badge.className = 'mokosuite-toggle-published badge bg-' + (pub ? 'success' : 'danger');
|
||||
badge.textContent = pub ? 'Published' : 'Unpublished';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Session\Session;
|
||||
|
||||
$items = $this->items;
|
||||
$total = $this->total;
|
||||
$filters = $this->filters;
|
||||
$token = Session::getFormToken();
|
||||
$input = Factory::getApplication()->getInput();
|
||||
$page = max(1, $input->getInt('page', 1));
|
||||
$pages = max(1, ceil($total / 50));
|
||||
?>
|
||||
|
||||
<div id="mokosuiteclient-snippets">
|
||||
<form method="get" action="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=snippets'); ?>" class="mb-3">
|
||||
<input type="hidden" name="option" value="com_mokosuiteclient">
|
||||
<input type="hidden" name="view" value="snippets">
|
||||
<div class="row g-2 align-items-end">
|
||||
<div class="col-md-4">
|
||||
<input type="text" name="filter_search" class="form-control form-control-sm" placeholder="Search by name or alias..." value="<?php echo htmlspecialchars($filters['search'], ENT_QUOTES, 'UTF-8'); ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select name="filter_published" class="form-select form-select-sm">
|
||||
<option value="">All States</option>
|
||||
<option value="1"<?php echo $filters['published'] === '1' ? ' selected' : ''; ?>>Published</option>
|
||||
<option value="0"<?php echo $filters['published'] === '0' ? ' selected' : ''; ?>>Unpublished</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-sm btn-primary"><span class="icon-search"></span> Filter</button>
|
||||
<a href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=snippets'); ?>" class="btn btn-sm btn-outline-secondary">Reset</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span><span class="icon-code"></span> Snippets</span>
|
||||
<span class="badge bg-secondary"><?php echo number_format($total); ?> total</span>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:5%">ID</th>
|
||||
<th>Name</th>
|
||||
<th>Alias</th>
|
||||
<th>Category</th>
|
||||
<th style="width:8%">Order</th>
|
||||
<th style="width:8%">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($items)): ?>
|
||||
<tr><td colspan="6" class="text-center text-muted py-4">No snippets found.</td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($items as $item): ?>
|
||||
<tr>
|
||||
<td><?php echo (int) $item->id; ?></td>
|
||||
<td>
|
||||
<?php if ($item->color): ?>
|
||||
<span style="display:inline-block;width:12px;height:12px;border-radius:2px;background:<?php echo htmlspecialchars($item->color, ENT_QUOTES, 'UTF-8'); ?>;vertical-align:middle;margin-right:4px;"></span>
|
||||
<?php endif; ?>
|
||||
<?php echo htmlspecialchars($item->name, ENT_QUOTES, 'UTF-8'); ?>
|
||||
<?php if ($item->description): ?>
|
||||
<br><small class="text-muted"><?php echo htmlspecialchars(mb_strimwidth($item->description, 0, 80, '...'), ENT_QUOTES, 'UTF-8'); ?></small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><code>{snippet <?php echo htmlspecialchars($item->alias, ENT_QUOTES, 'UTF-8'); ?>}</code></td>
|
||||
<td>
|
||||
<?php if ($item->category): ?>
|
||||
<span class="badge bg-info"><?php echo htmlspecialchars($item->category, ENT_QUOTES, 'UTF-8'); ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo (int) $item->ordering; ?></td>
|
||||
<td>
|
||||
<a href="#" class="mokosuite-toggle-published badge bg-<?php echo $item->published ? 'success' : 'danger'; ?>"
|
||||
data-table="mokosuiteclient_snippets" data-id="<?php echo (int) $item->id; ?>"
|
||||
data-token="<?php echo $token; ?>">
|
||||
<?php echo $item->published ? 'Published' : 'Unpublished'; ?>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($pages > 1): ?>
|
||||
<nav class="mt-3"><ul class="pagination pagination-sm justify-content-center">
|
||||
<?php for ($p = 1; $p <= $pages; $p++): ?>
|
||||
<li class="page-item<?php echo $p === $page ? ' active' : ''; ?>">
|
||||
<a class="page-link" href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=snippets&page=' . $p
|
||||
. ($filters['search'] ? '&filter_search=' . urlencode($filters['search']) : '')
|
||||
. ($filters['published'] !== '' ? '&filter_published=' . $filters['published'] : '')); ?>"><?php echo $p; ?></a>
|
||||
</li>
|
||||
<?php endfor; ?>
|
||||
</ul></nav>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('.mokosuite-toggle-published').forEach(function(el) {
|
||||
el.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
var table = this.dataset.table, id = this.dataset.id, token = this.dataset.token, badge = this;
|
||||
var fd = new FormData();
|
||||
fd.append('table', table);
|
||||
fd.append('id', id);
|
||||
fd.append(token, '1');
|
||||
fetch('index.php?option=com_mokosuiteclient&task=display.togglePublished&format=json', {
|
||||
method: 'POST', headers: {'X-Requested-With': 'XMLHttpRequest'}, body: fd
|
||||
}).then(function(r) { return r.json(); }).then(function(d) {
|
||||
if (d.success) {
|
||||
var pub = d.published;
|
||||
badge.className = 'mokosuite-toggle-published badge bg-' + (pub ? 'success' : 'danger');
|
||||
badge.textContent = pub ? 'Published' : 'Unpublished';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoSuiteClient
|
||||
* @subpackage com_mokosuiteclient
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Session\Session;
|
||||
|
||||
$items = $this->items;
|
||||
$total = $this->total;
|
||||
$filters = $this->filters;
|
||||
$token = Session::getFormToken();
|
||||
$input = Factory::getApplication()->getInput();
|
||||
$page = max(1, $input->getInt('page', 1));
|
||||
$pages = max(1, ceil($total / 50));
|
||||
?>
|
||||
|
||||
<div id="mokosuiteclient-templates">
|
||||
<form method="get" action="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=templates'); ?>" class="mb-3">
|
||||
<input type="hidden" name="option" value="com_mokosuiteclient">
|
||||
<input type="hidden" name="view" value="templates">
|
||||
<div class="row g-2 align-items-end">
|
||||
<div class="col-md-4">
|
||||
<input type="text" name="filter_search" class="form-control form-control-sm" placeholder="Search by name or alias..." value="<?php echo htmlspecialchars($filters['search'], ENT_QUOTES, 'UTF-8'); ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select name="filter_published" class="form-select form-select-sm">
|
||||
<option value="">All States</option>
|
||||
<option value="1"<?php echo $filters['published'] === '1' ? ' selected' : ''; ?>>Published</option>
|
||||
<option value="0"<?php echo $filters['published'] === '0' ? ' selected' : ''; ?>>Unpublished</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-sm btn-primary"><span class="icon-search"></span> Filter</button>
|
||||
<a href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=templates'); ?>" class="btn btn-sm btn-outline-secondary">Reset</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span><span class="icon-file-alt"></span> Content Templates</span>
|
||||
<span class="badge bg-secondary"><?php echo number_format($total); ?> total</span>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:5%">ID</th>
|
||||
<th>Name</th>
|
||||
<th>Alias</th>
|
||||
<th>Category</th>
|
||||
<th style="width:8%">Order</th>
|
||||
<th style="width:8%">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($items)): ?>
|
||||
<tr><td colspan="6" class="text-center text-muted py-4">No content templates found.</td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($items as $item): ?>
|
||||
<tr>
|
||||
<td><?php echo (int) $item->id; ?></td>
|
||||
<td>
|
||||
<?php if ($item->color): ?>
|
||||
<span style="display:inline-block;width:12px;height:12px;border-radius:2px;background:<?php echo htmlspecialchars($item->color, ENT_QUOTES, 'UTF-8'); ?>;vertical-align:middle;margin-right:4px;"></span>
|
||||
<?php endif; ?>
|
||||
<?php echo htmlspecialchars($item->name, ENT_QUOTES, 'UTF-8'); ?>
|
||||
<?php if ($item->description): ?>
|
||||
<br><small class="text-muted"><?php echo htmlspecialchars(mb_strimwidth($item->description, 0, 80, '...'), ENT_QUOTES, 'UTF-8'); ?></small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><code><?php echo htmlspecialchars($item->alias, ENT_QUOTES, 'UTF-8'); ?></code></td>
|
||||
<td>
|
||||
<?php if ($item->category): ?>
|
||||
<span class="badge bg-info"><?php echo htmlspecialchars($item->category, ENT_QUOTES, 'UTF-8'); ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo (int) $item->ordering; ?></td>
|
||||
<td>
|
||||
<a href="#" class="mokosuite-toggle-published badge bg-<?php echo $item->published ? 'success' : 'danger'; ?>"
|
||||
data-table="mokosuiteclient_content_templates" data-id="<?php echo (int) $item->id; ?>"
|
||||
data-token="<?php echo $token; ?>">
|
||||
<?php echo $item->published ? 'Published' : 'Unpublished'; ?>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($pages > 1): ?>
|
||||
<nav class="mt-3"><ul class="pagination pagination-sm justify-content-center">
|
||||
<?php for ($p = 1; $p <= $pages; $p++): ?>
|
||||
<li class="page-item<?php echo $p === $page ? ' active' : ''; ?>">
|
||||
<a class="page-link" href="<?php echo Route::_('index.php?option=com_mokosuiteclient&view=templates&page=' . $p
|
||||
. ($filters['search'] ? '&filter_search=' . urlencode($filters['search']) : '')
|
||||
. ($filters['published'] !== '' ? '&filter_published=' . $filters['published'] : '')); ?>"><?php echo $p; ?></a>
|
||||
</li>
|
||||
<?php endfor; ?>
|
||||
</ul></nav>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('.mokosuite-toggle-published').forEach(function(el) {
|
||||
el.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
var table = this.dataset.table, id = this.dataset.id, token = this.dataset.token, badge = this;
|
||||
var fd = new FormData();
|
||||
fd.append('table', table);
|
||||
fd.append('id', id);
|
||||
fd.append(token, '1');
|
||||
fetch('index.php?option=com_mokosuiteclient&task=display.togglePublished&format=json', {
|
||||
method: 'POST', headers: {'X-Requested-With': 'XMLHttpRequest'}, body: fd
|
||||
}).then(function(r) { return r.json(); }).then(function(d) {
|
||||
if (d.success) {
|
||||
var pub = d.published;
|
||||
badge.className = 'mokosuite-toggle-published badge bg-' + (pub ? 'success' : 'danger');
|
||||
badge.textContent = pub ? 'Published' : 'Unpublished';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -126,20 +126,31 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
fd.append(token, '1');
|
||||
|
||||
fetch(url, {method: 'POST', body: fd, headers: {'X-Requested-With': 'XMLHttpRequest'}})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (r) {
|
||||
return r.text().then(function (text) {
|
||||
try { return JSON.parse(text); }
|
||||
catch (e) { return {success: false, message: 'Server error: ' + text.substring(0, 200)}; }
|
||||
});
|
||||
})
|
||||
.then(function (d) {
|
||||
var msg = d.message || (d.success ? 'Heartbeat sent to HQ.' : 'Heartbeat failed.');
|
||||
if (d.success) {
|
||||
Joomla.renderMessages({message: [d.message || 'Heartbeat sent to HQ.']});
|
||||
if (icon) { icon.className = 'icon-check'; icon.style.color = '#198754'; }
|
||||
Joomla.renderMessages({message: [msg]});
|
||||
} else {
|
||||
Joomla.renderMessages({error: [d.message || 'Heartbeat failed.']});
|
||||
if (icon) { icon.className = 'icon-times'; icon.style.color = '#dc3545'; }
|
||||
Joomla.renderMessages({error: [msg]});
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
Joomla.renderMessages({error: ['Network error sending heartbeat.']});
|
||||
.catch(function (err) {
|
||||
if (icon) { icon.className = 'icon-times'; icon.style.color = '#dc3545'; }
|
||||
Joomla.renderMessages({error: ['Heartbeat failed: ' + (err.message || 'network error')]});
|
||||
})
|
||||
.finally(function () {
|
||||
btn.disabled = false;
|
||||
if (icon) icon.className = 'icon-upload';
|
||||
setTimeout(function () {
|
||||
if (icon) { icon.className = 'icon-upload'; icon.style.color = ''; }
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>MokoSuiteClient admin dashboard and REST API. Provides a control panel for managing MokoSuiteClient feature plugins, site health monitoring, and remote management endpoints.</description>
|
||||
|
||||
<namespace path="src">Moko\Component\MokoSuiteClient</namespace>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>MOD_MOKOSUITECLIENT_CACHE_DESC</description>
|
||||
<namespace path="src">Moko\Module\MokoSuiteClientCache</namespace>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>MOD_MOKOSUITECLIENT_CATEGORIES_DESC</description>
|
||||
<namespace path="src">Moko\Module\MokoSuiteClientCategories</namespace>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>MOD_MOKOSUITECLIENT_CPANEL_DESC</description>
|
||||
<namespace path="src">Moko\Module\MokoSuiteClientCpanel</namespace>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>MokoSuiteClient admin sidebar menu — renders a dedicated MokoSuiteClient section in the admin menu before Joomla's default menu.</description>
|
||||
<namespace path="src">Moko\Module\MokoSuiteClientMenu</namespace>
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ $allViews = [
|
||||
['icon' => 'fa-solid fa-file-lines', 'title' => 'Templates', 'link' => 'index.php?option=com_mokosuiteclient&view=templates', 'acl' => 'mokosuiteclient.templates.manage'],
|
||||
['icon' => 'fa-solid fa-right-left', 'title' => 'Replacements', 'link' => 'index.php?option=com_mokosuiteclient&view=replacements','acl' => 'mokosuiteclient.replacements.manage'],
|
||||
['icon' => 'fa-solid fa-shuffle', 'title' => 'Conditions', 'link' => 'index.php?option=com_mokosuiteclient&view=conditions', 'acl' => 'mokosuiteclient.conditions.manage'],
|
||||
['icon' => 'icon-cube', 'title' => 'Modules', 'link' => 'index.php?option=com_mokosuiteclient&view=modules', 'acl' => 'core.admin'],
|
||||
['icon' => 'icon-database', 'title' => 'Database Tools', 'link' => 'index.php?option=com_mokosuiteclient&view=database', 'acl' => 'core.admin'],
|
||||
['icon' => 'icon-trash', 'title' => 'Cache Cleanup', 'link' => 'index.php?option=com_mokosuiteclient&view=cleanup', 'acl' => 'mokosuiteclient.cache'],
|
||||
['icon' => 'icon-power-off', 'title' => 'Feature Plugins', 'link' => 'index.php?option=com_plugins&filter[folder]=system&filter[search]=mokosuiteclient', 'acl' => 'core.admin'],
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* DEFGROUP: Joomla.Plugin
|
||||
* INGROUP: MokoSuiteClient
|
||||
* REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
* VERSION: 02.48.52
|
||||
* VERSION: 02.51.06
|
||||
* PATH: /src/Extension/MokoSuiteClient.php
|
||||
* NOTE: Core system plugin for MokoSuiteClient admin tools suite
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: Joomla.Plugin
|
||||
* INGROUP: MokoSuiteClient
|
||||
* VERSION: 02.48.52
|
||||
* VERSION: 02.51.06
|
||||
* PATH: /src/Field/ArticlesField.php
|
||||
* BRIEF: List field that populates with published Joomla articles
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: Joomla.Plugin
|
||||
* INGROUP: MokoSuiteClient
|
||||
* VERSION: 02.48.52
|
||||
* VERSION: 02.51.06
|
||||
* PATH: /src/Field/CopyableTokenField.php
|
||||
* BRIEF: Read-only token field with a copy-to-clipboard button
|
||||
*/
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<license>GNU General Public License version 3 or later; see LICENSE.md</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>MokoSuiteClient core system plugin — coordinates feature plugins, heartbeat, health checks, and admin customizations.</description>
|
||||
<namespace path=".">Moko\Plugin\System\MokoSuiteClient</namespace>
|
||||
<scriptfile>script.php</scriptfile>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* DEFGROUP: Joomla.Plugin
|
||||
* INGROUP: MokoSuiteClient
|
||||
* REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
* VERSION: 02.48.52
|
||||
* VERSION: 02.51.06
|
||||
* PATH: /src/script.php
|
||||
* BRIEF: Installation script for MokoSuiteClient plugin
|
||||
* NOTE: Handles installation, update, and uninstallation tasks including language override deployment
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* DEFGROUP: Joomla.Plugin
|
||||
* INGROUP: MokoSuiteClient
|
||||
* REPO: https://github.com/mokoconsulting-tech/mokosuiteclient
|
||||
* VERSION: 02.48.52
|
||||
* VERSION: 02.51.06
|
||||
* PATH: /src/services/provider.php
|
||||
* BRIEF: Service provider for dependency injection in Joomla 5.x
|
||||
* NOTE: Registers the plugin with Joomla's DI container
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>PLG_SYSTEM_MOKOSUITECLIENT_BACKUP_DESC</description>
|
||||
<namespace path="src">Moko\Plugin\System\MokoSuiteClientBackup</namespace>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>PLG_SYSTEM_MOKOSUITECLIENT_DBIP_DESC</description>
|
||||
<namespace path="src">Moko\Plugin\System\MokoSuiteClientDBIP</namespace>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>PLG_SYSTEM_MOKOSUITECLIENT_DEVTOOLS_DESC</description>
|
||||
<namespace path="src">Moko\Plugin\System\MokoSuiteClientDevTools</namespace>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>PLG_SYSTEM_MOKOSUITECLIENT_FIREWALL_DESC</description>
|
||||
<namespace path="src">Moko\Plugin\System\MokoSuiteClientFirewall</namespace>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>PLG_SYSTEM_MOKOSUITECLIENT_LICENSE_DESC</description>
|
||||
<namespace path="src">Moko\Plugin\System\MokoSuiteClientLicense</namespace>
|
||||
<files><folder>src</folder><folder>services</folder><folder>language</folder></files>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>PLG_SYSTEM_MOKOSUITECLIENT_OFFLINE_DESC</description>
|
||||
<namespace path="src">Moko\Plugin\System\MokoSuiteClientOffline</namespace>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>PLG_SYSTEM_MOKOSUITECLIENT_TENANT_DESC</description>
|
||||
<namespace path="src">Moko\Plugin\System\MokoSuiteClientTenant</namespace>
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<license>GNU General Public License version 3 or later; see LICENSE</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>PLG_TASK_MOKOSUITECLIENTDEMO_DESC</description>
|
||||
<namespace path="src">Moko\Plugin\Task\MokoSuiteClientDemo</namespace>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* INGROUP: MokoSuiteClient
|
||||
* REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient
|
||||
* PATH: /src/packages/plg_system_mokosuiteclient/Service/DemoResetService.php
|
||||
* VERSION: 02.48.52
|
||||
* VERSION: 02.51.06
|
||||
* BRIEF: Content-only snapshot/restore for demo site reset
|
||||
*/
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<license>GNU General Public License version 3 or later; see LICENSE</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>PLG_TASK_MOKOSUITECLIENTSYNC_DESC</description>
|
||||
<namespace path="src">Moko\Plugin\Task\MokoSuiteClientSync</namespace>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* INGROUP: MokoSuiteClient
|
||||
* REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient
|
||||
* PATH: /src/packages/plg_system_mokosuiteclient/Service/ContentSyncReceiver.php
|
||||
* VERSION: 02.48.52
|
||||
* VERSION: 02.51.06
|
||||
* BRIEF: Receiver-side content sync — applies incoming payload to local DB
|
||||
*/
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* INGROUP: MokoSuiteClient
|
||||
* REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteClient
|
||||
* PATH: /src/packages/plg_system_mokosuiteclient/Service/ContentSyncService.php
|
||||
* VERSION: 02.48.52
|
||||
* VERSION: 02.51.06
|
||||
* BRIEF: Sender-side content sync — builds payload and pushes to remote sites
|
||||
*/
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<description>Joomla Web Services API routes for MokoSuiteClient site management — health checks, cache, updates, backups, and site info.</description>
|
||||
<namespace path="src">Moko\Plugin\WebServices\MokoSuiteClient</namespace>
|
||||
<files>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<extension type="package" method="upgrade">
|
||||
<name>Package - MokoSuiteClient</name>
|
||||
<packagename>mokosuiteclient</packagename>
|
||||
<version>02.48.52</version>
|
||||
<version>02.51.06</version>
|
||||
<creationDate>2026-06-02</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
|
||||
Reference in New Issue
Block a user