Compare commits

..

1 Commits

Author SHA1 Message Date
gitea-actions[bot] 01be74376b chore(version): pre-release bump to 01.35.05-dev [skip ci]
Publish to Composer / Publish Package (release) Failing after 7s
2026-06-23 15:41:01 +00:00
15 changed files with 24 additions and 131 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: mokocli.Automation
# VERSION: 01.36.00
# VERSION: 01.35.05
# BRIEF: Auto-create feature branch when an issue is opened
name: "Universal: Issue Branch"
+12 -8
View File
@@ -1,14 +1,18 @@
# Changelog
## [Unreleased]
## [01.36.00] --- 2026-06-23
## [01.36.00] --- 2026-06-23
## [01.35.04] --- 2026-06-23
## [01.35.04] --- 2026-06-23
## [01.35.03] --- 2026-06-23
## [01.35.03] --- 2026-06-23
## [01.35.01] --- 2026-06-23
## [01.35.01] --- 2026-06-23
## [01.35.00] --- 2026-06-23
## [01.35.00] --- 2026-06-23
### Added
- SFTP remote storage with SSH key file authentication — key stored securely in database
- CLI restore options: --files-only, --db-only, --no-preserve-config, --password
+1 -1
View File
@@ -1,6 +1,6 @@
# MokoSuiteBackup
<!-- VERSION: 01.36.00 -->
<!-- VERSION: 01.35.05 -->
Full-site backup and restore for Joomla — database, files, and configuration.
@@ -72,14 +72,12 @@
/>
<field
name="archive_name_format"
type="PlaceholderText"
type="text"
label="COM_MOKOJOOMBACKUP_FIELD_ARCHIVE_NAME_FORMAT"
description="COM_MOKOJOOMBACKUP_FIELD_ARCHIVE_NAME_FORMAT_DESC"
default="[host]_[datetime]_profile[profile_id]"
maxlength="512"
hint="[host]_[datetime]_profile[profile_id]"
placeholders="[host],[datetime],[date],[time],[year],[month],[day],[hour],[minute],[second],[profile_id],[profile_name],[site_name],[type],[random]"
addfieldprefix="Joomla\Component\MokoSuiteBackup\Administrator\Field"
/>
<field
name="include_mokorestore"
@@ -7,7 +7,7 @@
-->
<extension type="component" method="upgrade">
<name>MokoSuiteBackup</name>
<version>01.36.00</version>
<version>01.35.05</version>
<creationDate>2026-06-02</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -100,17 +100,6 @@ class FolderPickerField extends FormField
<span class="icon-question-circle" aria-hidden="true"></span>
</button>
</div>
<div class="mt-1 mb-1" id="{$id}_placeholders" style="display:flex; flex-wrap:wrap; gap:4px;">
<span class="text-muted small me-1" style="line-height:24px;">Insert:</span>
<button type="button" class="btn btn-outline-secondary btn-sm py-0 px-1 moko-ph-insert" data-field="{$id}" data-ph="[HOME]" title="Home directory">[HOME]</button>
<button type="button" class="btn btn-outline-secondary btn-sm py-0 px-1 moko-ph-insert" data-field="{$id}" data-ph="[DEFAULT_DIR]" title="Default backup dir">[DEFAULT_DIR]</button>
<button type="button" class="btn btn-outline-secondary btn-sm py-0 px-1 moko-ph-insert" data-field="{$id}" data-ph="[host]" title="Server hostname">[host]</button>
<button type="button" class="btn btn-outline-secondary btn-sm py-0 px-1 moko-ph-insert" data-field="{$id}" data-ph="[site_name]" title="Joomla site name">[site_name]</button>
<button type="button" class="btn btn-outline-secondary btn-sm py-0 px-1 moko-ph-insert" data-field="{$id}" data-ph="[date]" title="Date (Ymd)">[date]</button>
<button type="button" class="btn btn-outline-secondary btn-sm py-0 px-1 moko-ph-insert" data-field="{$id}" data-ph="[profile_id]" title="Profile ID">[profile_id]</button>
<button type="button" class="btn btn-outline-secondary btn-sm py-0 px-1 moko-ph-insert" data-field="{$id}" data-ph="[profile_name]" title="Profile name">[profile_name]</button>
<button type="button" class="btn btn-outline-secondary btn-sm py-0 px-1 moko-ph-insert" data-field="{$id}" data-ph="[type]" title="Backup type">[type]</button>
</div>
<div class="mt-1" id="{$id}_status">
<small class="{$statusClass}">
<span class="{$statusIcon}" aria-hidden="true"></span>
@@ -166,26 +155,6 @@ class FolderPickerField extends FormField
</div>
<script>
(function() {
/* Clickable placeholder insertion at cursor position */
document.querySelectorAll('.moko-ph-insert[data-field="{$id}"]').forEach(function(btn) {
btn.addEventListener('click', function(e) {
e.preventDefault();
var target = document.getElementById(this.getAttribute('data-field'));
var ph = this.getAttribute('data-ph');
if (!target) return;
var start = target.selectionStart || 0;
var end = target.selectionEnd || 0;
var val = target.value;
target.value = val.substring(0, start) + ph + val.substring(end);
/* Move cursor to after the inserted placeholder */
var newPos = start + ph.length;
target.setSelectionRange(newPos, newPos);
target.focus();
/* Trigger input event so status updates */
target.dispatchEvent(new Event('input', { bubbles: true }));
});
});
var fieldId = '{$id}';
var btn = document.getElementById(fieldId + '_btn');
var browser = document.getElementById(fieldId + '_browser');
@@ -1,78 +0,0 @@
<?php
/**
* @package MokoSuiteBackup
* @subpackage com_mokosuitebackup
* @author Moko Consulting <hello@mokoconsulting.tech>
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*
* Text field with clickable placeholder pills that insert at cursor position.
* Used for backup directory and archive name format fields.
*/
namespace Joomla\Component\MokoSuiteBackup\Administrator\Field;
defined('_JEXEC') or die;
use Joomla\CMS\Form\FormField;
class PlaceholderTextField extends FormField
{
protected $type = 'PlaceholderText';
protected function getInput(): string
{
$value = htmlspecialchars($this->value ?? $this->default ?? '', ENT_QUOTES, 'UTF-8');
$id = htmlspecialchars($this->id, ENT_QUOTES, 'UTF-8');
$name = htmlspecialchars($this->name, ENT_QUOTES, 'UTF-8');
$hint = htmlspecialchars($this->element['hint'] ?? '', ENT_QUOTES, 'UTF-8');
$max = (int) ($this->element['maxlength'] ?? 512);
$placeholderAttr = (string) ($this->element['placeholders'] ?? '');
$placeholders = array_filter(array_map('trim', explode(',', $placeholderAttr)));
if (empty($placeholders)) {
$placeholders = ['[host]', '[date]', '[datetime]', '[time]', '[year]', '[month]', '[day]',
'[hour]', '[minute]', '[second]', '[profile_id]', '[profile_name]', '[site_name]', '[type]', '[random]'];
}
$html = '<input type="text" name="' . $name . '" id="' . $id . '" value="' . $value . '"'
. ' class="form-control" maxlength="' . $max . '"'
. ($hint ? ' placeholder="' . $hint . '"' : '') . '>';
$html .= '<div class="mt-1" style="display:flex; flex-wrap:wrap; gap:4px;">';
$html .= '<span class="text-muted small me-1" style="line-height:24px;">Insert:</span>';
foreach ($placeholders as $ph) {
$html .= '<button type="button" class="btn btn-outline-secondary btn-sm py-0 px-1 moko-ph-insert"'
. ' data-field="' . $id . '" data-ph="' . htmlspecialchars($ph) . '">'
. htmlspecialchars($ph) . '</button>';
}
$html .= '</div>';
$html .= <<<JS
<script>
document.querySelectorAll('.moko-ph-insert[data-field="{$id}"]').forEach(function(btn) {
btn.addEventListener('click', function(e) {
e.preventDefault();
var target = document.getElementById(this.getAttribute('data-field'));
var ph = this.getAttribute('data-ph');
if (!target) return;
var start = target.selectionStart || 0;
var end = target.selectionEnd || 0;
var val = target.value;
target.value = val.substring(0, start) + ph + val.substring(end);
var newPos = start + ph.length;
target.setSelectionRange(newPos, newPos);
target.focus();
target.dispatchEvent(new Event('input', { bubbles: true }));
});
});
</script>
JS;
return $html;
}
}
@@ -7,7 +7,7 @@
-->
<extension type="plugin" group="actionlog" method="upgrade">
<name>Action Log - MokoSuiteBackup</name>
<version>01.36.00</version>
<version>01.35.05</version>
<creationDate>2026-06-04</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -7,7 +7,7 @@
-->
<extension type="plugin" group="console" method="upgrade">
<name>Console - MokoSuiteBackup</name>
<version>01.36.00</version>
<version>01.35.05</version>
<creationDate>2026-06-04</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -7,7 +7,7 @@
-->
<extension type="plugin" group="content" method="upgrade">
<name>Content - MokoSuiteBackup</name>
<version>01.36.00</version>
<version>01.35.05</version>
<creationDate>2026-06-04</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="quickicon" method="upgrade">
<name>Quick Icon - MokoSuiteBackup</name>
<version>01.36.00</version>
<version>01.35.05</version>
<creationDate>2026-06-02</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -7,7 +7,7 @@
-->
<extension type="plugin" group="system" method="upgrade">
<name>System - MokoSuiteBackup</name>
<version>01.36.00</version>
<version>01.35.05</version>
<creationDate>2026-06-02</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -7,7 +7,7 @@
-->
<extension type="plugin" group="task" method="upgrade">
<name>Task - MokoSuiteBackup</name>
<version>01.36.00</version>
<version>01.35.05</version>
<creationDate>2026-06-02</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -7,7 +7,7 @@
-->
<extension type="plugin" group="webservices" method="upgrade">
<name>Web Services - MokoSuiteBackup</name>
<version>01.36.00</version>
<version>01.35.05</version>
<creationDate>2026-06-02</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
+1 -1
View File
@@ -8,7 +8,7 @@
<extension type="package" method="upgrade">
<name>Package - MokoSuiteBackup</name>
<packagename>mokosuitebackup</packagename>
<version>01.36.00</version>
<version>01.35.05</version>
<creationDate>2026-06-02</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>