From 8994ebdad2abfa488dc40a18a3ce9dfad20995d5 Mon Sep 17 00:00:00 2001 From: Steve Sutton Date: Wed, 9 Oct 2019 08:47:19 -0400 Subject: [PATCH] Plugin update for server,sites,plugins worked on list for server plugins and sites. sites and plugins now show list of which plugin or site are installed. plugins detail page now allows editing of the site_plugins record. --- classes/data/dataPlugins.php | 16 +- classes/data/dataServers.php | 8 + classes/data/dataSitePlugins.php | 182 ++++++++++++++++++ classes/data/dataSites.php | 2 +- models/admin/plugins/index.php | 74 ++----- models/admin/plugins/plugins.php | 70 ++++++- models/admin/plugins/servers.php | 38 ++++ models/admin/plugins/sites.php | 6 + .../create_database_V0.0.1.sql | 1 + views/admin/plugins/plugin-detail.html | 15 +- views/admin/plugins/plugin-site.html | 79 ++++++++ views/admin/plugins/server-detail.html | 134 +++++++++++++ views/admin/plugins/servers.html | 2 +- views/admin/plugins/site-detail.html | 10 + 14 files changed, 560 insertions(+), 77 deletions(-) create mode 100644 classes/data/dataSitePlugins.php create mode 100644 views/admin/plugins/plugin-site.html create mode 100644 views/admin/plugins/server-detail.html diff --git a/classes/data/dataPlugins.php b/classes/data/dataPlugins.php index a1e229a..d41257b 100644 --- a/classes/data/dataPlugins.php +++ b/classes/data/dataPlugins.php @@ -73,8 +73,7 @@ class GlmDataPlugins extends GlmDataAbstract */ public $fields = false; - public $postStats = false; - public $postSent = false; + public $postOldVersions = false; /** * Constructor @@ -170,6 +169,19 @@ class GlmDataPlugins extends GlmDataAbstract */ public function entryPostProcessing($r, $a) { + if ( $this->postOldVersions ) { + // Get sites that have old versions of this plugin. + $r['oldDevVersions'] = $this->wpdb->get_results( + $this->wpdb->prepare( + "SELECT S.name + FROM " . GLM_MEMBERS_PLUGINS_PLUGIN_DB_PREFIX . "sites S + LEFT OUTER JOIN " . GLM_MEMBERS_PLUGINS_PLUGIN_DB_PREFIX . "site_plugins SP ON (S.id = SP.site) + WHERE SP.plugin = %d", + $r['id'] + ), + ARRAY_A + ); + } return $r; } diff --git a/classes/data/dataServers.php b/classes/data/dataServers.php index 6341cd1..0f3efac 100644 --- a/classes/data/dataServers.php +++ b/classes/data/dataServers.php @@ -118,6 +118,14 @@ class GlmDataServers extends GlmDataAbstract 'use' => 'a' ), + // Production + 'production' => array( + 'field' => 'production', + 'type' => 'checkbox', + 'required' => false, + 'use' => 'a' + ), + // Name 'name' => array ( 'field' => 'name', diff --git a/classes/data/dataSitePlugins.php b/classes/data/dataSitePlugins.php new file mode 100644 index 0000000..1e96a1f --- /dev/null +++ b/classes/data/dataSitePlugins.php @@ -0,0 +1,182 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataEvents.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +/** + * GlmDataEmailMessages class + * + * PHP version 5 + * + * @category Data + * @package GLM Member DB + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataMembers.php,v 1.0 2011/01/25 19:31:47 cscott + * Exp $ + */ +class GlmDataSitePlugin extends GlmDataAbstract +{ + + /** + * WordPress Database Object + * + * @var $wpdb + * @access public + */ + public $wpdb; + /** + * Plugin Configuration Data + * + * @var $config + * @access public + */ + public $config; + /** + * Data Table Name + * + * @var $table + * @access public + */ + public $table; + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter + * functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * @param array $config Configuration array + * @param bool $limitedEdit Flag to say indicate limited edit requested + * + * @return void + * @access public + */ + public function __construct($wpdb, $config, $limitedEdit = false) + { + + // If this class is not being extended along with existing $wpdb and $config + if (!$this->wpdb) { + + // Save WordPress Database object + $this->wpdb = $wpdb; + + // Save plugin configuration object + $this->config = $config; + + } + + /* + * Table Name + */ + $this->table = GLM_MEMBERS_PLUGINS_PLUGIN_DB_PREFIX . 'site_plugins'; + + /* + * Table Data Fields + */ + + $this->fields = array ( + + 'id' => array ( + 'field' => 'id', + 'type' => 'integer', + 'view_only' => true, + 'use' => 'a' + ), + + // Site + 'site' => array ( + 'field' => 'site', + 'type' => 'pointer', + 'p_table' => GLM_MEMBERS_PLUGINS_PLUGIN_DB_PREFIX . 'sites', + 'p_field' => 'name', + 'p_orderby' => 'name', + 'required' => true, + 'force_list' => true, + 'use' => 'a' + ), + + // Plugin + 'plugin' => array ( + 'field' => 'plugin', + 'type' => 'pointer', + 'p_table' => GLM_MEMBERS_PLUGINS_PLUGIN_DB_PREFIX . 'plugins', + 'p_field' => 'name', + 'p_orderby' => 'name', + 'required' => true, + 'force_list' => true, + 'use' => 'a' + ), + + // Prod Version + 'prod_version' => array ( + 'field' => 'prod_version', + 'type' => 'text', + 'required' => true, + 'use' => 'a' + ), + + // Development URL + 'dev_version' => array ( + 'field' => 'dev_version', + 'type' => 'text', + 'required' => true, + 'use' => 'a' + ), + + ); + + } + + /** + * Entry Post Processing Call-Back Method + * + * Perform post-processing for all result entries. + * + * In this case we're using it to append an array of category + * data to each member result and also sort by member name. + * + * @param array $r Array of field result data for a single entry + * @param string $a Action being performed (l, i, g, ...) + * + * @return object Class object + * + */ + public function entryPostProcessing($r, $a) + { + return $r; + } + + +} diff --git a/classes/data/dataSites.php b/classes/data/dataSites.php index 0cee0a2..f16d670 100644 --- a/classes/data/dataSites.php +++ b/classes/data/dataSites.php @@ -174,7 +174,7 @@ class GlmDataSites extends GlmDataAbstract 'map_key' => array ( 'field' => 'map_key', 'type' => 'text', - 'required' => true, + 'required' => false, 'use' => 'a' ), diff --git a/models/admin/plugins/index.php b/models/admin/plugins/index.php index 781e992..1302784 100644 --- a/models/admin/plugins/index.php +++ b/models/admin/plugins/index.php @@ -14,8 +14,9 @@ */ // Load Members data abstract -// require_once GLM_MEMBERS_PLUGINS_PLUGIN_CLASS_PATH.'/data/dataEmailMessages.php'; -// require_once GLM_MEMBERS_PLUGINS_PLUGIN_CLASS_PATH.'/data/dataEmailTemplates.php'; +require_once GLM_MEMBERS_PLUGINS_PLUGIN_CLASS_PATH . '/data/dataPlugins.php'; +require_once GLM_MEMBERS_PLUGINS_PLUGIN_CLASS_PATH . '/data/dataSites.php'; +require_once GLM_MEMBERS_PLUGINS_PLUGIN_CLASS_PATH . '/data/dataSitePlugins.php'; /* * This class performs the work for the default action of the "Members" menu @@ -125,70 +126,17 @@ class GlmMembersAdmin_plugins_index // extends GlmDataEmailMessages switch ( $option ) { - case 'plugins': - $view = 'plugins'; - // Get list of plugins. - $plugins = [ - [ - 'id' => 1, - 'name' => 'glm-member-db', - ], - [ - 'id' => 2, - 'name' => 'glm-member-db-contacts', - ], - [ - 'id' => 3, - 'name' => 'glm-member-db-events', - ], - ]; - $tData['plugins'] = $plugins; - break; + default: + $Plugins = new GlmDataPlugins( $this->wpdb, $this->config ); - case 'sites': - $view = 'sites'; - // Get list of Sites. - $sites = [ - [ - 'id' => 1, - 'name' => 'Baraga County', - ], - [ - 'id' => 2, - 'name' => 'Uptravel', - ], - [ - 'id' => 3, - 'name' => 'WMTA', - ], - ]; - $tData['sites'] = $sites; - break; + // Get list of Plugins. + // For this list display sites that need an update. + // $Plugins->postOldVersions = true; + $plugins = $Plugins->getResults( array( 'order' => 'T.name' ) ); - case 'servers': - $view = 'servers'; - $servers = [ - [ - 'id' => 1, - 'name' => 'dev55', - ], - [ - 'id' => 2, - 'name' => 'dev70', - ], - [ - 'id' => 3, - 'name' => 'eleusis', - ], - [ - 'id' => 4, - 'name' => 'norax', - ], - ]; - $tData['servers'] = $servers; - break; + // echo '
$plugins: ' . print_r( $plugins, true ) . '
'; + $tData['plugins'] = $plugins; - default: break; } diff --git a/models/admin/plugins/plugins.php b/models/admin/plugins/plugins.php index b6b6d37..f8c39f2 100644 --- a/models/admin/plugins/plugins.php +++ b/models/admin/plugins/plugins.php @@ -15,6 +15,7 @@ // Load Members data abstract require_once GLM_MEMBERS_PLUGINS_PLUGIN_CLASS_PATH.'/data/dataPlugins.php'; +require_once GLM_MEMBERS_PLUGINS_PLUGIN_CLASS_PATH.'/data/dataSitePlugins.php'; /* * This class performs the work for the default action of the "Members" menu @@ -124,27 +125,88 @@ class GlmMembersAdmin_plugins_plugins extends GlmDataPlugins switch ( $option ) { + case 'pluginSite': + $SitePlugins = new GlmDataSitePlugin( $this->wpdb, $this->config ); + $view = 'plugin-site'; + if ( isset( $_REQUEST['plugin_id'] ) && $id = filter_var( $_REQUEST['plugin_id'], FILTER_VALIDATE_INT ) ) { + // Get site id + if ( isset( $_REQUEST['site_id'] ) && $site = filter_var( $_REQUEST['site_id'], FILTER_VALIDATE_INT ) ) { + $sitePluginId = $this->wpdb->get_var( + $this->wpdb->prepare( + "SELECT id + FROM " . GLM_MEMBERS_PLUGINS_PLUGIN_DB_PREFIX . "site_plugins + WHERE site = %d + AND plugin = %d", + $site, + $id + ) + ); + $tData['sitePlugin'] = $SitePlugins->editEntry( $sitePluginId ); + } + } + break; + case 'save': if ( isset( $_REQUEST['plugin_id'] ) && $id = filter_var( $_REQUEST['plugin_id'], FILTER_VALIDATE_INT ) ) { $plugin = $this->updateEntry( $id ); - // echo '
$plugin: ' . print_r( $plugin, true ) . '
'; + } + + case 'savePluginSite': + $SitePlugins = new GlmDataSitePlugin( $this->wpdb, $this->config ); + if ( isset( $_REQUEST['id'] ) && $id = filter_var( $_REQUEST['id'], FILTER_VALIDATE_INT ) ) { + $sitePlugin = $SitePlugins->updateEntry( $id ); } case 'view': - $view = 'plugin-detail'; + $view = 'plugin-detail'; + $orderBy = 'S.name'; if ( isset( $_REQUEST['plugin_id'] ) && $id = filter_var( $_REQUEST['plugin_id'], FILTER_VALIDATE_INT ) ) { $plugin = $this->editEntry( $id ); $tData['plugin'] = $plugin; + if ( isset( $_REQUEST['order'] ) && $order = filter_var( $_REQUEST['order'], FILTER_SANITIZE_STRING ) ) { + switch ( $order ) { + case 'nameA': + $orderBy = 'S.name ASC'; + break; + case 'nameD': + $orderBy = 'S.name DESC'; + break; + case 'prod_serverA': + $orderBy = 'PS.name ASC,S.name ASC'; + break; + case 'prod_serverD': + $orderBy = 'PS.name DESC,S.name ASC'; + break; + case 'prod_versionA': + $orderBy = 'SP.prod_version ASC,S.name ASC'; + break; + case 'prod_versionD': + $orderBy = 'SP.prod_version DESC,S.name ASC'; + break; + case 'dev_serverA': + $orderBy = 'DS.name ASC,S.name ASC'; + break; + case 'dev_serverD': + $orderBy = 'DS.name DESC,S.name ASC'; + break; + case 'dev_versionA': + $orderBy = 'SP.dev_version ASC,S.name ASC'; + break; + case 'dev_versionD': + $orderBy = 'SP.dev_version DESC,S.name ASC'; + break; + } + } // Find all sites for this plugin. $tData['sites'] = $this->wpdb->get_results( $this->wpdb->prepare( - "SELECT S.name as site_name,SP.prod_version,SP.dev_version,PS.name as prod_server,DS.name as dev_server + "SELECT S.name as site_name,S.id,SP.prod_version,SP.dev_version,PS.name as prod_server,DS.name as dev_server FROM " . GLM_MEMBERS_PLUGINS_PLUGIN_DB_PREFIX . "site_plugins SP LEFT OUTER JOIN " . GLM_MEMBERS_PLUGINS_PLUGIN_DB_PREFIX . "sites S ON (S.id = SP.site) LEFT OUTER JOIN " . GLM_MEMBERS_PLUGINS_PLUGIN_DB_PREFIX . "servers PS ON (PS.id = S.prod_server) LEFT OUTER JOIN " . GLM_MEMBERS_PLUGINS_PLUGIN_DB_PREFIX . "servers DS ON (DS.id = S.dev_server) WHERE SP.plugin = %d - ORDER BY S.name", + ORDER BY $orderBy", $plugin['fieldData']['id'] ), ARRAY_A diff --git a/models/admin/plugins/servers.php b/models/admin/plugins/servers.php index ddac427..6eae634 100644 --- a/models/admin/plugins/servers.php +++ b/models/admin/plugins/servers.php @@ -124,6 +124,44 @@ class GlmMembersAdmin_plugins_servers extends GlmDataServers switch ( $option ) { + case 'save': + if ( isset( $_REQUEST['server_id'] ) && $id = filter_var( $_REQUEST['server_id'], FILTER_VALIDATE_INT ) ) { + $plugin = $this->updateEntry( $id ); + } + + case 'view': + $view = 'server-detail'; + if ( isset( $_REQUEST['server_id'] ) && $id = filter_var( $_REQUEST['server_id'], FILTER_VALIDATE_INT ) ) { + $server = $this->editEntry( $id ); + $tData['server'] = $server; + if ( $server['fieldData']['production']['value'] ) { + $tData['sites'] = $this->wpdb->get_results( + $this->wpdb->prepare( + "SELECT S.name as site_name,S.prod_url as url + FROM " . GLM_MEMBERS_PLUGINS_PLUGIN_DB_PREFIX . "sites S + LEFT OUTER JOIN " . GLM_MEMBERS_PLUGINS_PLUGIN_DB_PREFIX . "servers PS ON (PS.id = S.prod_server) + WHERE PS.id = %d + ORDER BY S.name", + $server['fieldData']['id'] + ), + ARRAY_A + ); + } else { + $tData['sites'] = $this->wpdb->get_results( + $this->wpdb->prepare( + "SELECT S.name as site_name,S.dev_url as url + FROM " . GLM_MEMBERS_PLUGINS_PLUGIN_DB_PREFIX . "sites S + LEFT OUTER JOIN " . GLM_MEMBERS_PLUGINS_PLUGIN_DB_PREFIX . "servers DS ON (DS.id = S.dev_server) + WHERE DS.id = %d + ORDER BY S.name", + $server['fieldData']['id'] + ), + ARRAY_A + ); + } + } + break; + default: break; } diff --git a/models/admin/plugins/sites.php b/models/admin/plugins/sites.php index 1a80575..74e8b45 100644 --- a/models/admin/plugins/sites.php +++ b/models/admin/plugins/sites.php @@ -124,6 +124,12 @@ class GlmMembersAdmin_plugins_sites extends GlmDataSites switch ( $option ) { + case 'save': + if ( isset( $_REQUEST['site_id'] ) && $id = filter_var( $_REQUEST['site_id'], FILTER_VALIDATE_INT ) ) { + $plugin = $this->updateEntry( $id ); + } + + case 'view': $view = 'site-detail'; if ( isset( $_REQUEST['site_id'] ) && $id = filter_var( $_REQUEST['site_id'], FILTER_VALIDATE_INT ) ) { diff --git a/setup/databaseScripts/create_database_V0.0.1.sql b/setup/databaseScripts/create_database_V0.0.1.sql index 9b3bbb9..c3b03b1 100644 --- a/setup/databaseScripts/create_database_V0.0.1.sql +++ b/setup/databaseScripts/create_database_V0.0.1.sql @@ -13,6 +13,7 @@ CREATE TABLE {prefix}servers ( location TINYTEXT NULL, php_version TINYTEXT NULL, mysql_version TINYTEXT NULL, + production BOOLEAN NOT NULL DEFAULT false, PRIMARY KEY (id) ); diff --git a/views/admin/plugins/plugin-detail.html b/views/admin/plugins/plugin-detail.html index a060d6f..e31ad5d 100644 --- a/views/admin/plugins/plugin-detail.html +++ b/views/admin/plugins/plugin-detail.html @@ -98,18 +98,21 @@ } +{$baseUrl = "{$thisUrl}?page={$thisPage}&glm_action={$thisAction}&option=view&plugin_id={$plugin.fieldData.id}"} +{$SitePluginUrl = "{$thisUrl}?page={$thisPage}&glm_action={$thisAction}plugin_id={$plugin.fieldData.id}"} + {if !empty($sites)} - - - - - + + + + + {foreach $sites as $site} - + diff --git a/views/admin/plugins/plugin-site.html b/views/admin/plugins/plugin-site.html new file mode 100644 index 0000000..c7550b0 --- /dev/null +++ b/views/admin/plugins/plugin-site.html @@ -0,0 +1,79 @@ +{* Plugin Site Add Edit Form *} + +{* Header *} +{include file="admin/header.html"} +

{$sitePlugin.fieldData.site.name} - {$sitePlugin.fieldData.plugin.name}

+ +{* Grid Start *} +{$ui = [ + 'nowrap' => false, + 'backgroundColor' => '', + 'sectionColor' => '' +]} +{include file='ui/f6/grid-start.html'} + +{* Form Start *} +{$ui = [ + 'id' => 'id', + 'action' => "{$thisUrl}?page={$thisPage}", + 'method' => 'post', + 'file' => false, + 'validate' => true, + 'validateFocusMsg' => true, + 'leaveModifiedFormCheck' => true +]} +{include file='ui/f6/form-start.html'} + + {* Form entry *} + {$data = $sitePlugin} + + + + + + + + {if !empty($smarty.request.order)} + + {/if} + + {* Prod Version *} + {$ui = [ + 'value' => $data.fieldData.prod_version, + 'field' => 'prod_version', + 'label' => 'Prod Version', + 'required' => $data.fieldRequired.prod_version, + 'errorText' => 'Prod Version is Required', + 'dataError' => $data.fieldFail.prod_version + ]} + {include file='ui/f6/text.html'} + + {* Dev Version *} + {$ui = [ + 'value' => $data.fieldData.dev_version, + 'field' => 'dev_version', + 'label' => 'Dev Version', + 'required' => $data.fieldRequired.dev_version, + 'errorText' => 'Dev Version is Required', + 'dataError' => $data.fieldFail.dev_version + ]} + {include file='ui/f6/text.html'} + + {* Submit *} + {$ui = [ + 'class' => 'primary', + 'label' => 'Save', + 'submit' => true, + 'id' => 'Save', + 'cancel' => "" + ]} + {include file='ui/f6/submit.html'} + +{* Form End *} +{include file='ui/f6/form-end.html'} + +{* Grid End *} +{include file='ui/f6/grid-end.html'} + +{* Footer *} +{include file="../../admin/footer.html"} diff --git a/views/admin/plugins/server-detail.html b/views/admin/plugins/server-detail.html new file mode 100644 index 0000000..041ae07 --- /dev/null +++ b/views/admin/plugins/server-detail.html @@ -0,0 +1,134 @@ +{* Server Detail View *} + +{* Headier *} +{include file="admin/header.html"} +

{$server.fieldData.name|default:'New Server'}

+ +{* Grid Start *} +{$ui = [ + 'nowrap' => false, + 'backgroundColor' => '', + 'sectionColor' => '' +]} +{include file='ui/f6/grid-start.html'} + +{* Form Start *} +{$ui = [ + 'id' => 'id', + 'action' => "{$thisUrl}?page={$thisPage}", + 'method' => 'post', + 'file' => false, + 'validate' => true, + 'validateFocusMsg' => true, + 'leaveModifiedFormCheck' => true +]} +{include file='ui/f6/form-start.html'} + + {$data = $server} + + + + + + {* Production *} + {$ui = [ + 'value' => $data.fieldData.production.value, + 'field' => 'production', + 'label' => 'Production', + 'required' => $data.fieldRequired.production, + 'errorText' => 'Production is Required', + 'dataError' => $data.fieldFail.production + ]} + {include file='ui/f6/checkbox.html'} + + {* Name *} + {$ui = [ + 'value' => $data.fieldData.name, + 'field' => 'name', + 'label' => 'Name', + 'required' => $data.fieldRequired.name, + 'errorText' => 'Name is Required', + 'dataError' => $data.fieldFail.name + ]} + {include file='ui/f6/text.html'} + + {* Location *} + {$ui = [ + 'value' => $data.fieldData.location, + 'field' => 'location', + 'label' => 'Location', + 'required' => $data.fieldRequired.location, + 'errorText' => 'Location is Required', + 'dataError' => $data.fieldFail.location + ]} + {include file='ui/f6/text.html'} + + {* PHP Version *} + {$ui = [ + 'value' => $data.fieldData.php_version, + 'field' => 'php_version', + 'label' => 'PHP Version', + 'required' => $data.fieldRequired.php_version, + 'errorText' => 'PHP Version is Required', + 'dataError' => $data.fieldFail.php_version + ]} + {include file='ui/f6/text.html'} + + {* Mysql Version *} + {$ui = [ + 'value' => $data.fieldData.mysql_version, + 'field' => 'mysql_version', + 'label' => 'Mysql Version', + 'required' => $data.fieldRequired.mysql_version, + 'errorText' => 'Mysql Version is Required', + 'dataError' => $data.fieldFail.mysql_version + ]} + {include file='ui/f6/text.html'} + + {* Save *} + {$ui = [ + 'class' => 'primary', + 'label' => 'Save', + 'submit' => true, + 'id' => 'form-save', + 'cancel' => "" + ]} + {include file='ui/f6/submit.html'} + +{* Form End *} +{include file='ui/f6/form-end.html'} + + + +{if !empty($sites)} +
Site NameProd ServerProd VersionDev ServerDev VersionSite NameProd ServerProd VersionDev ServerDev Version
{$site.site_name}{$site.site_name} {$site.prod_server} {$site.prod_version} {$site.dev_server}
+ + + + + {foreach $sites as $site} + + + + + {/foreach} +
Site NameURL
{$site.site_name}{$site.url}
+{/if} + +{* Grid End *} +{include file='ui/f6/grid-end.html'} + + + +{* Footer *} +{include file="../../admin/footer.html"} diff --git a/views/admin/plugins/servers.html b/views/admin/plugins/servers.html index 9e5579a..55f025a 100644 --- a/views/admin/plugins/servers.html +++ b/views/admin/plugins/servers.html @@ -19,7 +19,7 @@ {foreach $servers as $server} {$server.id} - {$server.name} + {$server.name} {$server.location} {$server.php_version} {$server.mysql_version} diff --git a/views/admin/plugins/site-detail.html b/views/admin/plugins/site-detail.html index 1935d5d..3040ccc 100644 --- a/views/admin/plugins/site-detail.html +++ b/views/admin/plugins/site-detail.html @@ -137,6 +137,16 @@ ]} {include file='ui/f6/checkbox.html'} + {* Save *} + {$ui = [ + 'class' => 'primary', + 'label' => 'Save', + 'submit' => true, + 'id' => 'form-save', + 'cancel' => "" + ]} + {include file='ui/f6/submit.html'} + {* Form End *} {include file='ui/f6/form-end.html'} -- 2.17.1