From 437a8428de0464764bbfa7c7a96c14bde72fdb73 Mon Sep 17 00:00:00 2001 From: Peter Schulze Date: Wed, 24 Apr 2024 11:42:10 +0200 Subject: [PATCH 01/11] history rework --- .gitignore | 1 + .../fragments/yform/manager/history.diff.php | 209 ++++++++++++++ plugins/manager/lang/de_de.lang | 20 +- plugins/manager/lang/en_gb.lang | 37 ++- plugins/manager/lang/es_es.lang | 41 ++- plugins/manager/lang/sv_se.lang | 25 ++ plugins/manager/lib/yform_history_helper.php | 190 ++++++++++++ plugins/manager/pages/data_history.php | 271 +++++++++++++----- 8 files changed, 716 insertions(+), 78 deletions(-) create mode 100644 plugins/manager/fragments/yform/manager/history.diff.php create mode 100644 plugins/manager/lib/yform_history_helper.php diff --git a/.gitignore b/.gitignore index 62099da2e..c5d8e9fc2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ vendor/ .phpunit.result.cache .php-cs-fixer.cache +/.idea/* diff --git a/plugins/manager/fragments/yform/manager/history.diff.php b/plugins/manager/fragments/yform/manager/history.diff.php new file mode 100644 index 000000000..a63879cdd --- /dev/null +++ b/plugins/manager/fragments/yform/manager/history.diff.php @@ -0,0 +1,209 @@ +getVar('history_id', null); +$datasetId = $this->getVar('dataset_id', null); +$currentDataset = $this->getVar('current_dataset', null); + +/* @var $table rex_yform_manager_table */ +$table = $this->getVar('table', null); + +$sql = rex_sql::factory(); +$timestamp = (string) $sql->setQuery(sprintf('SELECT `timestamp` FROM %s WHERE id = %d', rex::getTable('yform_history'), $historyId))->getValue('timestamp'); + +$data = $sql->getArray(sprintf('SELECT * FROM %s WHERE history_id = %d', rex::getTable('yform_history_field'), $historyId)); +$data = array_column($data, 'value', 'field'); + + +if(!is_null($historyId) && !is_null($table)): + +$diffs = [ + 'changed' => ['icon' => 'fas fa-not-equal', 'count' => 0, 'rows' => ''], + 'added' => ['icon' => 'fas fa-layer-plus', 'count' => 0, 'rows' => ''], + 'removed' => ['icon' => 'far fa-layer-minus', 'count' => 0, 'rows' => ''], + 'unchanged' => ['icon' => 'fas fa-equals', 'count' => 0, 'rows' => ''], + // 'prev_changed' => ['icon' => 'fas fa-not-equal', 'count' => 0, 'rows' => ''], +]; + + +$fieldsInDataset = []; + +$tableFields = $table->getFields(); + +foreach ($table->getValueFields() as $field) { + if (!array_key_exists($field->getName(), $data)) { + if($currentDataset->hasValue($field->getName())) { + $diffs['added']['count']++; + $diffs['added']['rows'] .= ' + + ' . rex_yform_history_helper::getFieldTypeIcon($field) . ' ' . $field->getLabel() . ' + ' . rex_yform_history_helper::getFieldValue($field, $currentDataset, $table) . ' + ' . rex_i18n::msg('yform_history_diff_not_yet_existing') . ' + '; + } + + continue; + } + + $change = 'unchanged'; + + $fieldsInDataset[] = $field->getName(); + $historyValue = $data[$field->getName()]; + $currentValue = ($currentDataset->hasValue($field->getName()) ? $currentDataset->getValue($field->getName()) : '-'); + + $class = 'rex_yform_value_' . $field->getTypeName(); + + // count diffs + if(!$currentDataset->hasValue($field->getName())) { + $change = 'deleted'; + } elseif("" . $historyValue != "" . $currentValue) { + $change = 'changed'; + } + + $diffs[$change]['count']++; + + if (is_callable($class, 'getListValue') && !in_array($field->getTypeName(), ['text', 'textarea'])) { + /** @var $class rex_yform_value_abstract */ + + // to ensure correct replacement with list value, ensure datatype by current dataset + if(gettype($currentValue) != gettype($historyValue)) { + settype($historyValue, gettype($currentValue)); + } + + // get (formatted) value for history entry + $historyValue = $class::getListValue([ + 'value' => $historyValue, + 'subject' => $historyValue, + 'field' => $field->getName(), + 'params' => [ + 'field' => $field->toArray(), + 'fields' => $this->table->getFields(), + ], + ]); + + // get (formatted) value for current entry + if($currentDataset->hasValue($field->getName())) { + $currentValue = $class::getListValue([ + 'value' => $currentValue, + 'subject' => $currentValue, + 'field' => $field->getName(), + 'params' => [ + 'field' => $field->toArray(), + 'fields' => $tableFields, + ], + ]); + } else { + $currentValue = '-'; + } + } else { + $historyValue = rex_escape($historyValue); + $currentValue = rex_escape($currentValue); + } + + // diff values for specific fields + if($change == 'changed') { + switch($field->getTypeName()) { + case 'text': + case 'textarea': + $diff = rex_yform_history_helper::diffStringsToHtml($currentValue, $historyValue); + $historyValue = $diff; + break; + + default: + if($historyValue != $currentValue) { + $historyValue = '' . $historyValue . ''; + } + break; + } + } + + $diffs[$change]['rows'] .= ' + + ' . rex_yform_history_helper::getFieldTypeIcon($field) . ' ' . $field->getLabel() . ' + ' . $currentValue . ' + ' . $historyValue . ' + '; + + // remove field from dataset to collect meanwhile deleted fields + unset($data[$field->getName()]); +} + +foreach ($data as $field => $value) { + $diffs['removed']['count']++; + $diffs['removed']['rows'] .= ' + + ' . $field . ' + ' . rex_i18n::msg('yform_history_diff_no_longer_existing') . ' + ' . $value . ' + '; +} + +// build restore url +$restoreUrl = http_build_query([ + 'table_name' => $table->getTableName(), + 'func' => 'history', + 'subfunc' => 'restore', + 'data_id' => $datasetId, + 'history_id' => $historyId +]).http_build_query(rex_csrf_token::factory($this->getVar('csrf_key', ''))->getUrlParams()); + +$content = ' + + + + +'; + +echo $content; +endif; \ No newline at end of file diff --git a/plugins/manager/lang/de_de.lang b/plugins/manager/lang/de_de.lang index 9fd0f29c3..7cc4fc89b 100644 --- a/plugins/manager/lang/de_de.lang +++ b/plugins/manager/lang/de_de.lang @@ -1,5 +1,3 @@ -yform_function_button = Aktion - yform_manager = Table Manager navigation_manager = Tabellen @@ -14,7 +12,7 @@ yform_errors_occurred = Es sind Fehler aufgetreten yform_help_empty = Leereinträge können mit
"(empty)" gesucht werden yform_help_multipleselect = Mehrfachauswahl mit gedrückter CTRL/CMD Taste yform_updatetable_with_delete = mit Feldlöschung -yform_updatetable_with_delete_confirm = Wirklich aktualisieren mit Feldlöschung ? +yform_updatetable_with_delete_confirm = Wirklich aktualisieren mit Feldlöschung? yform_relation_move_first_data = Ausgewählten Datensatz an den Anfang verschieben yform_relation_move_up_data = Ausgewählten Datensatz nach oben verschieben @@ -93,6 +91,7 @@ yform_manager_table_features = Aktivierte Optionen yform_manager_type_id = Typ yform_manager_type_name = Typname +yform_manager_type_unknown = unbekannt yform_manager_tableset = Tableset yform_manager_table = Tabelle @@ -234,8 +233,10 @@ yform_manager_import_error_duplicatefielddefinition = Es gibt Felder, welche ide # history yform_history = Historie +yform_history_title = Historie für yform_history_dataset_id = Datensatz-ID yform_history_dataset = Datensatz +yform_history_dataset_current = Aktuelle Version yform_history_action = Aktion yform_history_action_create = erstellt yform_history_action_update = bearbeitet @@ -244,6 +245,7 @@ yform_history_user = Benutzer yform_history_timestamp = Zeitstempel yform_history_view = ansehen yform_history_restore = zurücksetzen +yform_history_restore_confirm = Wirklich auf diese Version zurücksetzen? yform_history_restore_this = Datensatz auf diese Version zurücksetzen yform_history_restore_success = Datensatz wurde zurückgesetzt. yform_history_restore_error = Datensatz konnte nicht zurückgesetzt werden. @@ -252,6 +254,18 @@ yform_history_delete_all = komplett yform_history_delete_older_3_months = älter als 3 Monate yform_history_delete_confirm = Historie wirklich löschen? yform_history_delete_success = Die Historien-Datensätze wurden gelöscht. +yform_history_revision = Revision/Änderung +yform_history_diff_headline_changed = Geänderte Werte +yform_history_diff_headline_unchanged = Unveränderte Werte +yform_history_diff_headline_added = Hinzugefügte Felder +yform_history_diff_headline_removed = Entfernte Felder +yform_history_diff_headline_prev_changed = Änderungen gegenüber vorheriger Version +yform_history_diff_to_current = Änderungen (zu aktuell) +yform_history_diff_to_previous = Änderungen (zu vorherig) +yform_history_diff_added = neu +yform_history_diff_removed = entfernt +yform_history_diff_not_yet_existing = noch nicht vorhanden +yform_history_diff_no_longer_existing = nicht mehr vorhanden yform_manager_show_form_notation = Formular-Code diff --git a/plugins/manager/lang/en_gb.lang b/plugins/manager/lang/en_gb.lang index 468e7df92..a65920aed 100644 --- a/plugins/manager/lang/en_gb.lang +++ b/plugins/manager/lang/en_gb.lang @@ -91,6 +91,7 @@ yform_manager_table_features = Activated options yform_manager_type_id = Type yform_manager_type_name = Type name +yform_manager_type_unknown = unknown yform_manager_tableset = Table set yform_manager_table = Table @@ -125,6 +126,9 @@ yform_manager_table_hidden = Visibility yform_hidden = hidden yform_visible = visible +yform_manager_actions_all = all actions +yform_manager_users_all = all users +yform_manager_history_date_notice = all entries before and equal to this date are displayed # edit.inc.php yform_thankyouforupdate = Record updated. @@ -163,9 +167,11 @@ yform_dataset_delete = Delete result reset yform_dataset_deleted = Result set deleted yform_dataset_delete_confirm = Delete result set? -yform_data = Record -yform_datas = Records -yform_manager_search = Search +yform_dataset_edit_confirm = Should all selected data records really be edited? + +yform_data = data record +yform_datas = data records +yform_manager_search = search yform_data_view = show @@ -227,8 +233,10 @@ yform_manager_import_error_duplicatefielddefinition = There are identical fields # history yform_history = History +yform_history_title = Historie for yform_history_dataset_id = Record ID yform_history_dataset = Record +yform_history_dataset_current = current version yform_history_action = Action yform_history_action_create = created yform_history_action_update = updated @@ -237,6 +245,7 @@ yform_history_user = User yform_history_timestamp = Timestamp yform_history_view = view yform_history_restore = revert +yform_history_restore_confirm = Really revert to this version? yform_history_restore_this = Revert record to this version yform_history_restore_success = Record reverted yform_history_restore_error = Record could not be reverted. @@ -245,6 +254,18 @@ yform_history_delete_all = completely yform_history_delete_older_3_months = older than 3 months yform_history_delete_confirm = Delete History? yform_history_delete_success = History records deleted. +yform_history_revision = revision/change +yform_history_diff_headline_changed = changed values +yform_history_diff_headline_unchanged = unchanged values +yform_history_diff_headline_added = added fields +yform_history_diff_headline_removed = removed fields +yform_history_diff_headline_prev_changed = changes compared to previous version +yform_history_diff_to_current = changes (to current) +yform_history_diff_to_previous = changes (to previous) +yform_history_diff_added = added +yform_history_diff_removed = removed +yform_history_diff_not_yet_existing = not yet existing +yform_history_diff_no_longer_existing = no longer existing yform_manager_show_form_notation = Form code @@ -285,3 +306,13 @@ yform_will_set_to = will be yform_field_add = Add field yform_field_update = Update field yform_field_db_type = Database field type + +yform_manager_table_data_view_roles = Data view limited to +yform_manager_table_data_edit_roles = Data editing limited to + +yform_manager_table_nopermission = No permission for this table + +yform_manager_tables_edit = Tables with editing permission +yform_manager_tables_view = Tables with view permission + +yform_structure_article_could_not_be_deleted = The article could not be deleted because it is used by the following data records: diff --git a/plugins/manager/lang/es_es.lang b/plugins/manager/lang/es_es.lang index 3e2bc3820..d983bf670 100644 --- a/plugins/manager/lang/es_es.lang +++ b/plugins/manager/lang/es_es.lang @@ -8,11 +8,11 @@ yform_alltables = Todas las tablas yform_back_to_overview = Volver al resumen yform_updatetable = Actualizar tabla (s) yform_tablesupdated = Table/n ha sido actualizado - +yform_errors_occurred = Se han producido errores yform_help_empty = Las entradas vacías se pueden buscar con
"(vacío)" yform_help_multipleselect = Selección múltiple con tecla CTRL/CMD presionada -yform_updatetable_with_delete = con eliminación de campo -yform_updatetable_with_delete_confirm = Esta seguro de actualizar con eliminación de campo? +yform_updatetable_with_delete = con eliminación de campos +yform_updatetable_with_delete_confirm = ¿Actualización real con eliminación de campos? yform_relation_move_first_data = Mueva el registro seleccionado al principio yform_relation_move_up_data = Mover el registro seleccionado hacia arriba @@ -91,6 +91,7 @@ yform_manager_table_features = Opciones activadas yform_manager_type_id = Tipo yform_manager_type_name = Nombre tipo +yform_manager_type_unknown = desconocido yform_manager_tableset = Tableset yform_manager_table = Tabla @@ -125,13 +126,18 @@ yform_manager_table_hidden = Visibilidad yform_hidden = Oculto yform_visible = Visible +yform_manager_actions_all = Todas las acciones +yform_manager_users_all = Todos los usuarios +yform_manager_history_date_notice = Se muestran todas las entradas anteriores e iguales a esta fecha # edit.inc.php yform_thankyouforupdate = Record ha sido actualizado. +yform_thankyouforupdates = Se han actualizado los registros de datos. yform_thankyouforentry = Registro fue ingresado yform_editdata = Editar registro [id: {0}] yform_editdata_collection = {0} editar registros yform_editdata_collection_error_abort = La transacción falló debido a un error: {0} +yform_clonedata = Clonar registro de datos [ID original: {0}] yform_adddata = Crear registro de datos yform_searchtext = Palabra clave yform_searchfields = Campos de tabla para buscar @@ -141,6 +147,8 @@ yform_function_button = Accion yform_add = Añadir yform_add_apply = Tomar el relevo yform_edit = Editar +yform_clone = Clon +yform_view = Mostrar yform_save = Guardar yform_save_apply = Tomar el relevo yform_delete = Borrar @@ -159,6 +167,8 @@ yform_dataset_delete = Eliminar resultado de datos yform_dataset_deleted = El resultado de los datos fue vaciado yform_dataset_delete_confirm = ¿Realmente vaciar el resultado de los datos? +yform_dataset_edit_confirm = ¿Deben procesarse realmente todos los registros de datos seleccionados? + yform_data = Registro yform_datas = Archivos yform_manager_search = Búsqueda @@ -223,8 +233,10 @@ yform_manager_import_error_duplicatefielddefinition = Hay campos que son idénti # history yform_history = historia +yform_history_title = Historia para yform_history_dataset_id = Identificación del registro yform_history_dataset = registro +yform_history_dataset_current = Versión actual yform_history_action = Acción yform_history_action_create = Creado yform_history_action_update = Editado @@ -233,6 +245,7 @@ yform_history_user = Usuario yform_history_timestamp = Fecha y hora yform_history_view = Vista yform_history_restore = Regreso +yform_history_restore_confirm = ¿Reiniciar realmente a esta versión? yform_history_restore_this = Restablecer registro a esta versión yform_history_restore_success = El registro ha sido reiniciado. yform_history_restore_error = El registro no se pudo restablecer. @@ -241,6 +254,18 @@ yform_history_delete_all = Completo yform_history_delete_older_3_months = Más de 3 meses yform_history_delete_confirm = ¿Realmente borras la historia? yform_history_delete_success = Los registros de historial han sido eliminados. +yform_history_revision = Revisión/modificación +yform_history_diff_headline_changed = Valores modificados +yform_history_diff_headline_unchanged = Valores sin cambios +yform_history_diff_headline_added = Campos añadidos +yform_history_diff_headline_removed = Campos eliminados +yform_history_diff_headline_prev_changed = Cambios respecto a la versión anterior +yform_history_diff_to_current = Cambios (al actual) +yform_history_diff_to_previous = Cambios (al anterior) +yform_history_diff_added = nuevo +yform_history_diff_removed = eliminado +yform_history_diff_not_yet_existing = aún no disponible +yform_history_diff_no_longer_existing = ya no está disponible yform_manager_show_form_notation = Código del formulario @@ -281,3 +306,13 @@ yform_will_set_to = Deberá yform_field_add = Añadir campo yform_field_update = Campo de actualización yform_field_db_type = Tipo de campo de base de datos + +yform_manager_table_data_view_roles = Vista de datos limitada a +yform_manager_table_data_edit_roles = Tratamiento de datos limitado a + +yform_manager_table_nopermission = No hay autorización para esta tabla + +yform_manager_tables_edit = Tablas con autorización de edición +yform_manager_tables_view = Tablas con autorización de vista + +yform_structure_article_could_not_be_deleted = El artículo no se ha podido borrar porque lo utilizan los siguientes registros de datos: diff --git a/plugins/manager/lang/sv_se.lang b/plugins/manager/lang/sv_se.lang index 625e2f5b2..1b780c478 100644 --- a/plugins/manager/lang/sv_se.lang +++ b/plugins/manager/lang/sv_se.lang @@ -91,6 +91,7 @@ yform_manager_table_features = Aktiverade optioner yform_manager_type_id = Typ yform_manager_type_name = Typnamn +yform_manager_type_unknown = okänd yform_manager_tableset = Tabellset yform_manager_table = Tabell @@ -125,6 +126,9 @@ yform_manager_table_hidden = Synlighet yform_hidden = Dold yform_visible = Synligt +yform_manager_actions_all = Alla åtgärder +yform_manager_users_all = Alla användare +yform_manager_history_date_notice = Alla poster före och lika med detta datum visas # edit.inc.php yform_thankyouforupdate = Datasatsen aktualiserades. @@ -133,6 +137,7 @@ yform_thankyouforentry = Datasatsen tillfogades. yform_editdata = Redigera datasats yform_editdata_collection = Redigera {0} datasatser yform_editdata_collection_error_abort = Transaktionen misslyckades på grund av fel: {0} +yform_clonedata = Klonad datapost [Ursprungligt ID: {0}] yform_adddata = Skapa datasats yform_searchtext = Sökbegrepp yform_searchfields = Fälten som ska sökas igenom @@ -142,6 +147,7 @@ yform_function_button = Handling yform_add = tillfoga yform_add_apply = ta över yform_edit = redigera +yform_clone = klon yform_view = visa yform_save = spara yform_save_apply = ta över @@ -161,6 +167,8 @@ yform_dataset_delete = Radera dataresultatet yform_dataset_deleted = Dataresultatet raderades yform_dataset_delete_confirm = Radera dataresultatet? +yform_dataset_edit_confirm = Vill du verkligen redigera alla valda poster? + yform_data = Datasats yform_datas = Dataset yform_manager_search = Sök @@ -225,8 +233,10 @@ yform_manager_import_error_duplicatefielddefinition = Det finns fält som är id # history yform_history = Historik +yform_history_title = Historik för yform_history_dataset_id = Datasats-ID yform_history_dataset = Datasats +yform_history_dataset_current = Aktuell version yform_history_action = Aktion yform_history_action_create = skapat yform_history_action_update = redigerat @@ -235,6 +245,7 @@ yform_history_user = Användare yform_history_timestamp = Tidstämpel yform_history_view = visa yform_history_restore = återgå +yform_history_restore_confirm = Vill du verkligen återställa till den här versionen? yform_history_restore_this = återställ datasatsen till den här versionen yform_history_restore_success = Data återställdes yform_history_restore_error = Data kunde inte återställas @@ -243,6 +254,18 @@ yform_history_delete_all = totalt yform_history_delete_older_3_months = äldre än 3 månader yform_history_delete_confirm = Vill du verkligen radera historiken? yform_history_delete_success = Poster från historiken raderades. +yform_history_revision = Revision/Förändring +yform_history_diff_headline_changed = Ändrade Värden +yform_history_diff_headline_unchanged = Oförändrade Värden +yform_history_diff_headline_added = Tillagda Fält +yform_history_diff_headline_removed = Borttagna Fält +yform_history_diff_headline_prev_changed = Ändringar Jämfört med Föregående Version +yform_history_diff_to_current = Förändringar (till aktuell) +yform_history_diff_to_previous = Förändringar (till föregående) +yform_history_diff_added = Tillagd +yform_history_diff_removed = Borttagen +yform_history_diff_not_yet_existing = Ännu Inte Existerande +yform_history_diff_no_longer_existing = Inte Längre Existerande yform_manager_show_form_notation = Formularkod @@ -291,3 +314,5 @@ yform_manager_table_nopermission = Ingen behörighet till den här tabellen yform_manager_tables_edit = Tabeller med redigeringsrättigheter yform_manager_tables_view = Tabeller med påsiktsrättigheter + +yform_structure_article_could_not_be_deleted = Artikeln kunde inte raderas eftersom den används av följande poster: diff --git a/plugins/manager/lib/yform_history_helper.php b/plugins/manager/lib/yform_history_helper.php new file mode 100644 index 000000000..52f78a4d2 --- /dev/null +++ b/plugins/manager/lib/yform_history_helper.php @@ -0,0 +1,190 @@ + 'question', + + 'checkbox' => 'square-check', + 'select' => 'list-check', + 'choice' => 'list-check', + 'choice_radio' => 'circle-dot', + 'choice_checkbox' => 'square-check', + 'date' => 'calendar', + 'datetime' => 'calendar-day', + 'datestamp' => 'calendar-day', + 'be_link' => 'link', + 'custom_link' => 'link', + 'be_media' => 'photo-film', + 'be_manager_relation' => 'database', + 'be_table' => 'table', + 'be_user' => 'user', + 'integer' => '1', + 'number' => '1', + 'ip' => 'network-wired', + 'generate_key' => 'key', + 'php' => 'code', + 'prio' => 'arrow-up-1-9', + 'signature' => 'signature', + 'submit' => 'fire', + 'time' => 'clock', + 'upload' => 'upload', + 'uuid' => 'key', + 'email' => 'at' + ]; + + const FIELD_TYPE_ICON_WEIGHT_CLASS = 'far'; + + /** + * detect diffs in 2 strings + * @param $old + * @param $new + * @return array|array[] + * @author Peter Schulze | p.schulze[at]bitshifters.de + * @created 17.04.2024 + * @copyright https://github.com/paulgb/simplediff | Paul Butler (paulgb) + */ + public static function diffStrings($old, $new):array + { + $matrix = array(); + $maxlen = 0; + + foreach ($old as $oindex => $ovalue) { + $nkeys = array_keys($new, $ovalue); + + foreach ($nkeys as $nindex) { + $matrix[$oindex][$nindex] = + isset($matrix[$oindex - 1][$nindex - 1]) ? + $matrix[$oindex - 1][$nindex - 1] + 1 : + 1 + ; + + if ($matrix[$oindex][$nindex] > $maxlen) { + $maxlen = $matrix[$oindex][$nindex]; + $omax = $oindex + 1 - $maxlen; + $nmax = $nindex + 1 - $maxlen; + } + } + } + + if ($maxlen == 0) { + return array(array('d' => $old, 'i' => $new)); + } + + return array_merge( + self::diffStrings(array_slice($old, 0, $omax), array_slice($new, 0, $nmax)), + array_slice($new, $nmax, $maxlen), + self::diffStrings(array_slice($old, $omax + $maxlen), array_slice($new, $nmax + $maxlen)) + ); + } + + /** + * detect diffs in 2 strings and return as html + * @param $old + * @param $new + * @return string + * @author Peter Schulze | p.schulze[at]bitshifters.de + * @created 17.04.2024 + * @copyright https://github.com/paulgb/simplediff | Paul Butler (paulgb) + */ + public static function diffStringsToHtml($old, $new) + { + $ret = ''; + $diff = self::diffStrings(preg_split("/[\s]+/", $old), preg_split("/[\s]+/", $new)); + + foreach ($diff as $k) { + if (is_array($k)) { + $ret .= + (!empty($k['d']) ? "" . implode(' ', $k['d']) . " " : ''). + (!empty($k['i']) ? "" . implode(' ', $k['i']) . " " : '') + ; + } else { + $ret .= $k . ' '; + } + } + + return $ret; + } + + /** + * get icon for yform field type + * @param rex_yform_manager_field $field + * @param bool $addPrefix + * @param bool $outputHtml print + * @param bool $addTooltip + * @param string $tooltipPlacement + * @return string + * @author Peter Schulze | p.schulze[at]bitshifters.de + * @created 22.04.2024 + */ + public static function getFieldTypeIcon(rex_yform_manager_field $field, bool $addPrefix = true, bool $outputHtml = true, bool $addTooltip = true, string $tooltipPlacement = 'top'):string + { + $icon = self::FIELD_TYPE_ICONS[$field->getTypeName()] ?? 'default'; + $tag = isset(self::FIELD_TYPE_ICONS[$field->getTypeName()]) ? 'i' : 'span'; + + switch($field->getTypeName()) { + case 'choice': + $expanded = (bool)(int)$field->getElement('expanded'); + $multiple = (bool)(int)$field->getElement('multiple'); + + if($expanded && $multiple) { + $icon = self::FIELD_TYPE_ICONS['choice_checkbox']; + } elseif($expanded) { + $icon = self::FIELD_TYPE_ICONS['choice_radio']; + } + break; + } + + return ($outputHtml ? '<' . + $tag . + ($addTooltip ? ' data-toggle="tooltip" data-placement="' . $tooltipPlacement . '" title="' . rex_i18n::msg('yform_manager_type_name') . ': ' . $field->getTypeName() . '"' : '') . + ' class="' : '' + ). + ($icon !== 'default' ? self::FIELD_TYPE_ICON_WEIGHT_CLASS . ' ' : '').($addPrefix ? 'rex-icon ' : '') . 'fa-' . $icon . + ($outputHtml ? '">' : ''); + } + + /** + * get field value + * @param rex_yform_manager_field $field + * @param rex_yform_manager_dataset $dataset + * @param rex_yform_manager_table $table + * @return string + * @author Peter Schulze | p.schulze[at]bitshifters.de + * @created 22.04.2024 + */ + public static function getFieldValue(rex_yform_manager_field $field, rex_yform_manager_dataset $dataset, rex_yform_manager_table $table): string { + $class = 'rex_yform_value_' . $field->getTypeName(); + $currentValue = ($dataset->hasValue($field->getName()) ? $dataset->getValue($field->getName()) : '-'); + + if (is_callable($class, 'getListValue') && !in_array($field->getTypeName(), ['text','textarea'])) { + /** @var $class rex_yform_value_abstract */ + + // get (formatted) value for current entry + if($dataset->hasValue($field->getName())) { + $currentValue = $class::getListValue([ + 'value' => $currentValue, + 'subject' => $currentValue, + 'field' => $field->getName(), + 'params' => [ + 'field' => $field->toArray(), + 'fields' => $table->getFields() + ], + ]); + } else { + $currentValue = '-'; + } + } else { + $currentValue = rex_escape($currentValue); + } + + return $currentValue; + } +} \ No newline at end of file diff --git a/plugins/manager/pages/data_history.php b/plugins/manager/pages/data_history.php index a41413600..0b15e4353 100644 --- a/plugins/manager/pages/data_history.php +++ b/plugins/manager/pages/data_history.php @@ -13,16 +13,18 @@ $historySearchUser = rex_request('historySearchUser', 'string', null); $historySearchAction = rex_request('historySearchAction', 'string', null); +$table = $this->table; + $dataset = null; if ($datasetId) { - $dataset = rex_yform_manager_dataset::getRaw($datasetId, $this->table->getTableName()); + $dataset = rex_yform_manager_dataset::getRaw($datasetId, $table->getTableName()); } else { $filterDataset = false; } $filterWhere = ''; if ($filterDataset) { - echo rex_view::info('' . rex_i18n::msg('yform_history_dataset_id') . ': ' . $datasetId); + // echo rex_view::info('' . rex_i18n::msg('yform_history_dataset_id') . ': ' . $datasetId); $filterWhere = ' AND dataset_id = ' . $datasetId; } @@ -48,64 +50,14 @@ } if ('view' === $subfunc && $dataset && $historyId) { - $sql = rex_sql::factory(); - $timestamp = (string) $sql->setQuery(sprintf('SELECT `timestamp` FROM %s WHERE id = %d', rex::getTable('yform_history'), $historyId))->getValue('timestamp'); - - $data = $sql->getArray(sprintf('SELECT * FROM %s WHERE history_id = %d', rex::getTable('yform_history_field'), $historyId)); - $data = array_column($data, 'value', 'field'); - - $rows = ''; - - foreach ($this->table->getValueFields() as $field) { - if (!array_key_exists($field->getName(), $data)) { - continue; - } - - $value = $data[$field->getName()]; - $class = 'rex_yform_value_' . $field->getTypeName(); - if (method_exists($class, 'getListValue')) { - $value = $class::getListValue([ - 'value' => $value, - 'subject' => $value, - 'field' => $field->getName(), - 'params' => [ - 'field' => $field->toArray(), - 'fields' => $this->table->getFields(), - ], - ]); - } else { - $value = rex_escape($value); - } - - $rows .= ' - - ' . $field->getLabel() . ' - ' . $value . ' - '; - } - - $content = ' - - - - '; - - rex_response::sendContent($content); + $historyDiff = new rex_fragment(); + $historyDiff->setVar('history_id', $historyId); + $historyDiff->setVar('dataset_id', $datasetId); + $historyDiff->setVar('current_dataset', $dataset); + $historyDiff->setVar('table', $table, false); + $historyDiff->setVar('csrf_key', $_csrf_key); + + rex_response::sendContent($historyDiff->parse('yform/manager/history.diff.php')); exit; } @@ -137,7 +89,7 @@ LEFT JOIN %s hf ON hf.history_id = h.id WHERE h.table_name = ? %s ', rex::getTable('yform_history'), rex::getTable('yform_history_field'), $where), - [$this->table->getTableName()], + [$table->getTableName()], ); echo rex_view::success(rex_i18n::msg('yform_history_delete_success')); @@ -146,29 +98,31 @@ $sql = rex_sql::factory(); $listQuery = 'SELECT - h.id as hid, dataset_id, + dataset_id, + h.id as hid, id as title, `action`, `user`, `timestamp` FROM ' . rex::getTable('yform_history') . ' h WHERE - `table_name` = ' . $sql->escape($this->table->getTableName()) . + `table_name` = ' . $sql->escape($table->getTableName()) . $filterWhere; $userQuery = 'SELECT distinct `user` FROM ' . rex::getTable('yform_history') . ' h WHERE - `table_name` = ' . $sql->escape($this->table->getTableName()); + `table_name` = ' . $sql->escape($table->getTableName()); $list = rex_list::factory($listQuery, defaultSort: [ + 'timestamp' => 'asc', 'hid' => 'asc', - 'timestamp' => 'desc', ]); +$list->addFormAttribute('class', 'history-list'); $users = $sql->getArray($userQuery); $users = array_combine(array_column($users, 'user'), array_column($users, 'user')); -$list->addParam('table_name', $this->table->getTableName()); +$list->addParam('table_name', $table->getTableName()); $list->addParam('func', 'history'); $list->addParam('_csrf_token', rex_csrf_token::factory($_csrf_key)->getValue()); @@ -194,6 +148,7 @@ } $list->removeColumn('id'); +$list->removeColumn('dataset_id'); $list->setColumnLabel('dataset_id', rex_i18n::msg('yform_history_dataset_id')); $list->setColumnLabel('title', rex_i18n::msg('yform_history_dataset')); @@ -229,13 +184,191 @@ return (new DateTime($params['subject']))->format('d.m.Y H:i:s'); }); -$list->addColumn('view', ' ' . rex_i18n::msg('yform_history_view'), -1, ['', '###VALUE###']); +$viewColumnBody = ' ' . rex_i18n::msg('yform_history_view'); +$restoreColumnBody = ' ' . rex_i18n::msg('yform_history_restore'); +$actionsCell = '###VALUE###'; +$normalCell = '###VALUE###'; + +$list->addColumn('view', $viewColumnBody, -1, ['', $actionsCell]); $list->setColumnParams('view', ['subfunc' => 'view', 'data_id' => '###dataset_id###', 'history_id' => '###hid###']); $list->addLinkAttribute('view', 'data-toggle', 'modal'); $list->addLinkAttribute('view', 'data-target', '#rex-yform-history-modal'); -$list->addColumn('restore', ' ' . rex_i18n::msg('yform_history_restore'), -1, ['', '###VALUE###']); + +$list->addColumn('restore', $restoreColumnBody, -1, ['', $actionsCell]); $list->setColumnParams('restore', ['subfunc' => 'restore', 'data_id' => '###dataset_id###', 'history_id' => '###hid###'] + rex_csrf_token::factory($_csrf_key)->getUrlParams()); +$list->addLinkAttribute('restore', 'onclick', 'return confirm(\'' . rex_i18n::msg('yform_history_restore_confirm') . '\');'); + +$historyDatasets = []; +$sql = rex_sql::factory(); + +// revision / number +$revision = 'revision'; +$list->addColumn($revision, '', 2, [ + ''.rex_i18n::msg('yform_history_revision').'', + '###VALUE###' +]); + +rex::setProperty('YFORM_HISTORY_REVISION', 0); + +$list->setColumnFormat( + $revision, + 'custom', + static function($a) use (&$rev, &$historyDatasets, &$table, &$sql, &$dataset) { + // early column ... store all values for current revision + $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0); + + $historyDatasets[$rev] = [ + 'values' => [], + 'added' => [], + 'added_current' => [], + 'removed' => [], + 'removed_current' => [], + ]; + + $data = $sql->getArray(sprintf('SELECT * FROM %s WHERE history_id = %d', rex::getTable('yform_history_field'), $a['list']->getValue('hid'))); + $data = array_column($data, 'value', 'field'); + + foreach ($table->getValueFields() as $field) { + $class = 'rex_yform_value_' . $field->getTypeName(); + + if (!array_key_exists($field->getName(), $data)) { + if(method_exists($class, 'getListValue')) { + $historyDatasets[$rev]['added'][$field->getName()] = $historyDatasets[$rev]['added_current'][$field->getName()] = true; + } + + continue; + } + + // set data + $historyDatasets[$rev]['values'][$field->getName()] = $data[$field->getName()]; + unset($data[$field->getName()]); + } + + // check for deleted fields in historic data + foreach ($data as $field => $value) { + $historyDatasets[$rev]['removed_current'][$field] = $value; + } + + // compare with prev + if(isset($historyDatasets[$rev - 1])) { + $prev = &$historyDatasets[$rev - 1]; + + // clean up added + foreach($historyDatasets[$rev]['added'] as $field => $true) { + if(isset($prev['added'][$field])) { + unset($prev['added'][$field]); + } + } + + // handle removed + foreach($prev['removed_current'] as $field => $value) { + if(!isset($historyDatasets[$rev]['removed_current'][$field])) { + $historyDatasets[$rev]['removed'][$field] = $value; + } + } + } + + rex::setProperty('YFORM_HISTORY_REVISION', $rev + 1); + // dump($historyDatasets); + return $rev; + } +); + +// changes compared to current dataset +$changesCurrent = 'changes_to_current'; +$list->addColumn($changesCurrent, '', 3, [ + ''.rex_i18n::msg('yform_history_diff_to_current').'', + '###VALUE###' +]); + +$viewColumnLayout = $list->getColumnLayout('view'); + +$list->setColumnFormat( + $changesCurrent, + 'custom', + static function($a) use (&$dataset, $table, $sql, &$historyDatasets, $actionsCell, $normalCell, $changesCurrent) { + $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0) - 1; + + $changes = 0; + $added = count($historyDatasets[$rev]['added_current']); + $removed = count($historyDatasets[$rev]['removed_current']); + + $historyDataset = &$historyDatasets[$rev]['values']; + + foreach ($table->getValueFields() as $field) { + if (!array_key_exists($field->getName(), $historyDataset)) { + continue; + } + + $historyValue = $historyDataset[$field->getName()]; + $currentValue = ($dataset->hasValue($field->getName()) ? $dataset->getValue($field->getName()) : '-'); + + if("".$historyValue != "".$currentValue) { + $changes++; + } + } + + // handle actions column + if($changes == 0) { + $a['list']->setColumnLayout($changesCurrent, ['', '###VALUE###']); + $a['list']->setColumnLayout('view', ['', '']); + $a['list']->setColumnLayout('restore', ['', '']); + } else { + $a['list']->setColumnLayout($changesCurrent, ['', $normalCell]); + $a['list']->setColumnLayout('view', ['', $actionsCell]); + $a['list']->setColumnLayout('restore', ['', $actionsCell]); + } + + return $changes. + ($added > 0 || $removed > 0 ? + ' ('.($added > 0 ? '+'.$added.' '.rex_i18n::msg('yform_history_diff_added') : ''). + ($removed > 0 ? ($added > 0 ? ', ' : '').'+'.$removed.' '.rex_i18n::msg('yform_history_diff_removed') : '') + .')' : '' + ); + } +); + +// changes compared to previous dataset +$changesPrev = 'changes_to_prev'; +$list->addColumn($changesPrev, '', 4, [ + ''.rex_i18n::msg('yform_history_diff_to_previous').'', + '###VALUE###' +]); + +$sql = rex_sql::factory(); + +$list->setColumnFormat( + $changesPrev, + 'custom', + static function($a) use (&$dataset, $table, $sql, &$historyDatasets) { + $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0) - 1; + + $changes = 0; + $added = (isset($historyDatasets[$rev - 1]) ? count($historyDatasets[$rev - 1]['added']) : 0); + $removed = count($historyDatasets[$rev]['removed']); + + $historyDataset = &$historyDatasets[$rev]['values']; + + if(isset($historyDatasets[$rev - 1])) { + $prevHistoryDataset = $historyDatasets[$rev - 1]['values']; + + foreach ($historyDataset as $field => $value) { + if("".$historyDataset[$field] != "".$prevHistoryDataset[$field]) { + $changes++; + // dump($rev.": ".$historyDataset[$field]." - ".$prevHistoryDataset[$field]." - ".$changes); + } + } + } + + return $changes. + ($added > 0 || $removed > 0 ? + ' ('.($added > 0 ? '+'.$added.' '.rex_i18n::msg('yform_history_diff_added') : ''). + ($removed > 0 ? ($added > 0 ? ', ' : '').'+'.$removed.' '.rex_i18n::msg('yform_history_diff_removed') : '') + .')' : '' + ); + } +); $content = $list->get(); @@ -313,7 +446,7 @@ $searchForm = $fragment->parse('core/page/section.php'); $fragment = new rex_fragment(); -$fragment->setVar('title', rex_i18n::msg('yform_history')); +$fragment->setVar('title', rex_i18n::msg('yform_history_title'). ' '.rex_i18n::msg('yform_history_dataset_id').': '.$datasetId.'', false); $fragment->setVar('options', $options, false); $fragment->setVar('content', $content, false); $searchList = $fragment->parse('core/page/section.php'); From 2cb0637e9bc0371f92947a6dd98067063e748fe6 Mon Sep 17 00:00:00 2001 From: Peter Schulze Date: Wed, 24 Apr 2024 12:32:17 +0200 Subject: [PATCH 02/11] cleanup (after rexstan use) --- .../fragments/yform/manager/history.diff.php | 22 ++++----- plugins/manager/lib/yform_history_helper.php | 46 +++++++++---------- plugins/manager/pages/data_history.php | 4 +- 3 files changed, 33 insertions(+), 39 deletions(-) diff --git a/plugins/manager/fragments/yform/manager/history.diff.php b/plugins/manager/fragments/yform/manager/history.diff.php index a63879cdd..000dcc92e 100644 --- a/plugins/manager/fragments/yform/manager/history.diff.php +++ b/plugins/manager/fragments/yform/manager/history.diff.php @@ -13,9 +13,9 @@ $table = $this->getVar('table', null); $sql = rex_sql::factory(); -$timestamp = (string) $sql->setQuery(sprintf('SELECT `timestamp` FROM %s WHERE id = %d', rex::getTable('yform_history'), $historyId))->getValue('timestamp'); +$timestamp = $sql->setQuery(sprintf('SELECT `timestamp` FROM %s WHERE id = :id', rex::getTable('yform_history')), [':id' => $historyId])->getValue('timestamp'); -$data = $sql->getArray(sprintf('SELECT * FROM %s WHERE history_id = %d', rex::getTable('yform_history_field'), $historyId)); +$data = $sql->getArray(sprintf('SELECT * FROM %s WHERE history_id = :history_id', rex::getTable('yform_history_field')), [':history_id' => $historyId]); $data = array_column($data, 'value', 'field'); @@ -60,17 +60,15 @@ // count diffs if(!$currentDataset->hasValue($field->getName())) { $change = 'deleted'; - } elseif("" . $historyValue != "" . $currentValue) { + } elseif("" . $historyValue !== "" . $currentValue) { $change = 'changed'; } $diffs[$change]['count']++; - if (is_callable($class, 'getListValue') && !in_array($field->getTypeName(), ['text', 'textarea'])) { - /** @var $class rex_yform_value_abstract */ - + if (is_callable([$class, 'getListValue']) && !in_array($field->getTypeName(), ['text', 'textarea'], true)) { // to ensure correct replacement with list value, ensure datatype by current dataset - if(gettype($currentValue) != gettype($historyValue)) { + if(gettype($currentValue) !== gettype($historyValue)) { settype($historyValue, gettype($currentValue)); } @@ -105,7 +103,7 @@ } // diff values for specific fields - if($change == 'changed') { + if($change === 'changed') { switch($field->getTypeName()) { case 'text': case 'textarea': @@ -114,7 +112,7 @@ break; default: - if($historyValue != $currentValue) { + if($historyValue !== $currentValue) { $historyValue = '' . $historyValue . ''; } break; @@ -165,14 +163,14 @@ foreach ($diffs as $change => $diff) { $content .= ' -
+
' . rex_i18n::msg('yform_history_diff_headline_' . $change) . ' [' . ($diff['count'] > 0 ? '' : '') . $diff['count'] . ($diff['count'] > 0 ? '' : '') . ']' . '
-
'; +
'; - if($diff['rows'] != '') { + if($diff['rows'] !== '') { $content .= ' diff --git a/plugins/manager/lib/yform_history_helper.php b/plugins/manager/lib/yform_history_helper.php index 52f78a4d2..8d20d5657 100644 --- a/plugins/manager/lib/yform_history_helper.php +++ b/plugins/manager/lib/yform_history_helper.php @@ -9,7 +9,7 @@ */ class rex_yform_history_helper { - const FIELD_TYPE_ICONS = [ + const array FIELD_TYPE_ICONS = [ 'question' => 'question', 'checkbox' => 'square-check', @@ -40,7 +40,7 @@ class rex_yform_history_helper 'email' => 'at' ]; - const FIELD_TYPE_ICON_WEIGHT_CLASS = 'far'; + const string FIELD_TYPE_ICON_WEIGHT_CLASS = 'far'; /** * detect diffs in 2 strings @@ -51,13 +51,13 @@ class rex_yform_history_helper * @created 17.04.2024 * @copyright https://github.com/paulgb/simplediff | Paul Butler (paulgb) */ - public static function diffStrings($old, $new):array + public static function diffStrings($old, $new): array { $matrix = array(); - $maxlen = 0; + $maxlen = $omax = $nmax = 0; foreach ($old as $oindex => $ovalue) { - $nkeys = array_keys($new, $ovalue); + $nkeys = array_keys($new, $ovalue, true); foreach ($nkeys as $nindex) { $matrix[$oindex][$nindex] = @@ -74,14 +74,14 @@ public static function diffStrings($old, $new):array } } - if ($maxlen == 0) { + if ($maxlen === 0) { return array(array('d' => $old, 'i' => $new)); } return array_merge( - self::diffStrings(array_slice($old, 0, $omax), array_slice($new, 0, $nmax)), + rex_yform_history_helper::diffStrings(array_slice($old, 0, $omax), array_slice($new, 0, $nmax)), array_slice($new, $nmax, $maxlen), - self::diffStrings(array_slice($old, $omax + $maxlen), array_slice($new, $nmax + $maxlen)) + rex_yform_history_helper::diffStrings(array_slice($old, $omax + $maxlen), array_slice($new, $nmax + $maxlen)) ); } @@ -94,20 +94,16 @@ public static function diffStrings($old, $new):array * @created 17.04.2024 * @copyright https://github.com/paulgb/simplediff | Paul Butler (paulgb) */ - public static function diffStringsToHtml($old, $new) + public static function diffStringsToHtml($old, $new): string { $ret = ''; - $diff = self::diffStrings(preg_split("/[\s]+/", $old), preg_split("/[\s]+/", $new)); + $diff = rex_yform_history_helper::diffStrings(preg_split("/[\s]+/", $old), preg_split("/[\s]+/", $new)); foreach ($diff as $k) { - if (is_array($k)) { - $ret .= - (!empty($k['d']) ? "" . implode(' ', $k['d']) . " " : ''). - (!empty($k['i']) ? "" . implode(' ', $k['i']) . " " : '') - ; - } else { - $ret .= $k . ' '; - } + $ret .= + (isset($k['d']) ? "" . implode(' ', $k['d']) . " " : ''). + (isset($k['i']) ? "" . implode(' ', $k['i']) . " " : '') + ; } return $ret; @@ -126,8 +122,8 @@ public static function diffStringsToHtml($old, $new) */ public static function getFieldTypeIcon(rex_yform_manager_field $field, bool $addPrefix = true, bool $outputHtml = true, bool $addTooltip = true, string $tooltipPlacement = 'top'):string { - $icon = self::FIELD_TYPE_ICONS[$field->getTypeName()] ?? 'default'; - $tag = isset(self::FIELD_TYPE_ICONS[$field->getTypeName()]) ? 'i' : 'span'; + $icon = rex_yform_history_helper::FIELD_TYPE_ICONS[$field->getTypeName()] ?? 'default'; + $tag = isset(rex_yform_history_helper::FIELD_TYPE_ICONS[$field->getTypeName()]) ? 'i' : 'span'; switch($field->getTypeName()) { case 'choice': @@ -135,9 +131,9 @@ public static function getFieldTypeIcon(rex_yform_manager_field $field, bool $ad $multiple = (bool)(int)$field->getElement('multiple'); if($expanded && $multiple) { - $icon = self::FIELD_TYPE_ICONS['choice_checkbox']; + $icon = rex_yform_history_helper::FIELD_TYPE_ICONS['choice_checkbox']; } elseif($expanded) { - $icon = self::FIELD_TYPE_ICONS['choice_radio']; + $icon = rex_yform_history_helper::FIELD_TYPE_ICONS['choice_radio']; } break; } @@ -147,7 +143,7 @@ public static function getFieldTypeIcon(rex_yform_manager_field $field, bool $ad ($addTooltip ? ' data-toggle="tooltip" data-placement="' . $tooltipPlacement . '" title="' . rex_i18n::msg('yform_manager_type_name') . ': ' . $field->getTypeName() . '"' : '') . ' class="' : '' ). - ($icon !== 'default' ? self::FIELD_TYPE_ICON_WEIGHT_CLASS . ' ' : '').($addPrefix ? 'rex-icon ' : '') . 'fa-' . $icon . + ($icon !== 'default' ? rex_yform_history_helper::FIELD_TYPE_ICON_WEIGHT_CLASS . ' ' : '').($addPrefix ? 'rex-icon ' : '') . 'fa-' . $icon . ($outputHtml ? '">' : ''); } @@ -164,8 +160,8 @@ public static function getFieldValue(rex_yform_manager_field $field, rex_yform_m $class = 'rex_yform_value_' . $field->getTypeName(); $currentValue = ($dataset->hasValue($field->getName()) ? $dataset->getValue($field->getName()) : '-'); - if (is_callable($class, 'getListValue') && !in_array($field->getTypeName(), ['text','textarea'])) { - /** @var $class rex_yform_value_abstract */ + if (is_callable([$class, 'getListValue']) && !in_array($field->getTypeName(), ['text','textarea'], true)) { + /** @var rex_yform_value_abstract $class */ // get (formatted) value for current entry if($dataset->hasValue($field->getName())) { diff --git a/plugins/manager/pages/data_history.php b/plugins/manager/pages/data_history.php index 0b15e4353..75d940c84 100644 --- a/plugins/manager/pages/data_history.php +++ b/plugins/manager/pages/data_history.php @@ -214,7 +214,7 @@ $list->setColumnFormat( $revision, 'custom', - static function($a) use (&$rev, &$historyDatasets, &$table, &$sql, &$dataset) { + static function($a) use (&$rev, &$historyDatasets, &$table, &$sql) { // early column ... store all values for current revision $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0); @@ -287,7 +287,7 @@ static function($a) use (&$rev, &$historyDatasets, &$table, &$sql, &$dataset) { $list->setColumnFormat( $changesCurrent, 'custom', - static function($a) use (&$dataset, $table, $sql, &$historyDatasets, $actionsCell, $normalCell, $changesCurrent) { + static function($a) use (&$dataset, $table, &$historyDatasets, $actionsCell, $normalCell, $changesCurrent) { $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0) - 1; $changes = 0; From 9f87f9580d981f1a7cd8bd53c32f6b8f8a7e3271 Mon Sep 17 00:00:00 2001 From: Peter Schulze Date: Wed, 24 Apr 2024 12:49:14 +0200 Subject: [PATCH 03/11] fixing bad fixes (reverting const types, since only php 8.3+ | bringing back else area | --- plugins/manager/lib/yform_history_helper.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/plugins/manager/lib/yform_history_helper.php b/plugins/manager/lib/yform_history_helper.php index 8d20d5657..eeb478a1c 100644 --- a/plugins/manager/lib/yform_history_helper.php +++ b/plugins/manager/lib/yform_history_helper.php @@ -9,7 +9,7 @@ */ class rex_yform_history_helper { - const array FIELD_TYPE_ICONS = [ + const FIELD_TYPE_ICONS = [ 'question' => 'question', 'checkbox' => 'square-check', @@ -40,7 +40,7 @@ class rex_yform_history_helper 'email' => 'at' ]; - const string FIELD_TYPE_ICON_WEIGHT_CLASS = 'far'; + const FIELD_TYPE_ICON_WEIGHT_CLASS = 'far'; /** * detect diffs in 2 strings @@ -100,10 +100,14 @@ public static function diffStringsToHtml($old, $new): string $diff = rex_yform_history_helper::diffStrings(preg_split("/[\s]+/", $old), preg_split("/[\s]+/", $new)); foreach ($diff as $k) { - $ret .= - (isset($k['d']) ? "" . implode(' ', $k['d']) . " " : ''). - (isset($k['i']) ? "" . implode(' ', $k['i']) . " " : '') - ; + if (is_array($k)) { + $ret .= + (isset($k['d']) && count($k['d']) > 0 ? "" . implode(' ', $k['d']) . " " : ''). + (isset($k['i']) && count($k['i']) > 0 ? "" . implode(' ', $k['i']) . " " : '') + ; + } else { + $ret .= $k . ' '; + } } return $ret; From ee81d88450165a5fdbf6686b5928c71c34a47e5a Mon Sep 17 00:00:00 2001 From: Peter Schulze Date: Wed, 24 Apr 2024 12:52:49 +0200 Subject: [PATCH 04/11] more cleanup ... --- plugins/manager/pages/data_history.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/manager/pages/data_history.php b/plugins/manager/pages/data_history.php index 75d940c84..f5c9b933a 100644 --- a/plugins/manager/pages/data_history.php +++ b/plugins/manager/pages/data_history.php @@ -341,7 +341,7 @@ static function($a) use (&$dataset, $table, &$historyDatasets, $actionsCell, $no $list->setColumnFormat( $changesPrev, 'custom', - static function($a) use (&$dataset, $table, $sql, &$historyDatasets) { + static function($a) use (&$historyDatasets) { $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0) - 1; $changes = 0; From 900e25c1050cdd8d17f1d64e64891b24f83db1ee Mon Sep 17 00:00:00 2001 From: Peter Schulze Date: Wed, 24 Apr 2024 16:18:21 +0200 Subject: [PATCH 05/11] ran cs-fix --- .../fragments/yform/manager/history.diff.php | 182 +++++++++--------- plugins/manager/lib/yform_history_helper.php | 72 ++++--- plugins/manager/pages/data_history.php | 67 ++++--- 3 files changed, 163 insertions(+), 158 deletions(-) diff --git a/plugins/manager/fragments/yform/manager/history.diff.php b/plugins/manager/fragments/yform/manager/history.diff.php index 000dcc92e..4ef878c88 100644 --- a/plugins/manager/fragments/yform/manager/history.diff.php +++ b/plugins/manager/fragments/yform/manager/history.diff.php @@ -9,7 +9,7 @@ $datasetId = $this->getVar('dataset_id', null); $currentDataset = $this->getVar('current_dataset', null); -/* @var $table rex_yform_manager_table */ +/** @var rex_yform_manager_table $table */ $table = $this->getVar('table', null); $sql = rex_sql::factory(); @@ -18,120 +18,118 @@ $data = $sql->getArray(sprintf('SELECT * FROM %s WHERE history_id = :history_id', rex::getTable('yform_history_field')), [':history_id' => $historyId]); $data = array_column($data, 'value', 'field'); +if(null !== $historyId && null !== $table): -if(!is_null($historyId) && !is_null($table)): + $diffs = [ + 'changed' => ['icon' => 'fas fa-not-equal', 'count' => 0, 'rows' => ''], + 'added' => ['icon' => 'fas fa-layer-plus', 'count' => 0, 'rows' => ''], + 'removed' => ['icon' => 'far fa-layer-minus', 'count' => 0, 'rows' => ''], + 'unchanged' => ['icon' => 'fas fa-equals', 'count' => 0, 'rows' => ''], + // 'prev_changed' => ['icon' => 'fas fa-not-equal', 'count' => 0, 'rows' => ''], + ]; -$diffs = [ - 'changed' => ['icon' => 'fas fa-not-equal', 'count' => 0, 'rows' => ''], - 'added' => ['icon' => 'fas fa-layer-plus', 'count' => 0, 'rows' => ''], - 'removed' => ['icon' => 'far fa-layer-minus', 'count' => 0, 'rows' => ''], - 'unchanged' => ['icon' => 'fas fa-equals', 'count' => 0, 'rows' => ''], - // 'prev_changed' => ['icon' => 'fas fa-not-equal', 'count' => 0, 'rows' => ''], -]; + $fieldsInDataset = []; + $tableFields = $table->getFields(); -$fieldsInDataset = []; - -$tableFields = $table->getFields(); - -foreach ($table->getValueFields() as $field) { - if (!array_key_exists($field->getName(), $data)) { - if($currentDataset->hasValue($field->getName())) { - $diffs['added']['count']++; - $diffs['added']['rows'] .= ' + foreach ($table->getValueFields() as $field) { + if (!array_key_exists($field->getName(), $data)) { + if($currentDataset->hasValue($field->getName())) { + ++$diffs['added']['count']; + $diffs['added']['rows'] .= ' - + '; + } + + continue; } - continue; - } + $change = 'unchanged'; - $change = 'unchanged'; + $fieldsInDataset[] = $field->getName(); + $historyValue = $data[$field->getName()]; + $currentValue = ($currentDataset->hasValue($field->getName()) ? $currentDataset->getValue($field->getName()) : '-'); - $fieldsInDataset[] = $field->getName(); - $historyValue = $data[$field->getName()]; - $currentValue = ($currentDataset->hasValue($field->getName()) ? $currentDataset->getValue($field->getName()) : '-'); + $class = 'rex_yform_value_' . $field->getTypeName(); - $class = 'rex_yform_value_' . $field->getTypeName(); + // count diffs + if(!$currentDataset->hasValue($field->getName())) { + $change = 'deleted'; + } elseif('' . $historyValue !== '' . $currentValue) { + $change = 'changed'; + } - // count diffs - if(!$currentDataset->hasValue($field->getName())) { - $change = 'deleted'; - } elseif("" . $historyValue !== "" . $currentValue) { - $change = 'changed'; - } + ++$diffs[$change]['count']; - $diffs[$change]['count']++; + if (is_callable([$class, 'getListValue']) && !in_array($field->getTypeName(), ['text', 'textarea'], true)) { + // to ensure correct replacement with list value, ensure datatype by current dataset + if(gettype($currentValue) !== gettype($historyValue)) { + settype($historyValue, gettype($currentValue)); + } - if (is_callable([$class, 'getListValue']) && !in_array($field->getTypeName(), ['text', 'textarea'], true)) { - // to ensure correct replacement with list value, ensure datatype by current dataset - if(gettype($currentValue) !== gettype($historyValue)) { - settype($historyValue, gettype($currentValue)); - } - - // get (formatted) value for history entry - $historyValue = $class::getListValue([ - 'value' => $historyValue, - 'subject' => $historyValue, - 'field' => $field->getName(), - 'params' => [ - 'field' => $field->toArray(), - 'fields' => $this->table->getFields(), - ], - ]); - - // get (formatted) value for current entry - if($currentDataset->hasValue($field->getName())) { - $currentValue = $class::getListValue([ - 'value' => $currentValue, - 'subject' => $currentValue, + // get (formatted) value for history entry + $historyValue = $class::getListValue([ + 'value' => $historyValue, + 'subject' => $historyValue, 'field' => $field->getName(), 'params' => [ 'field' => $field->toArray(), - 'fields' => $tableFields, + 'fields' => $this->table->getFields(), ], ]); + + // get (formatted) value for current entry + if($currentDataset->hasValue($field->getName())) { + $currentValue = $class::getListValue([ + 'value' => $currentValue, + 'subject' => $currentValue, + 'field' => $field->getName(), + 'params' => [ + 'field' => $field->toArray(), + 'fields' => $tableFields, + ], + ]); + } else { + $currentValue = '-'; + } } else { - $currentValue = '-'; + $historyValue = rex_escape($historyValue); + $currentValue = rex_escape($currentValue); } - } else { - $historyValue = rex_escape($historyValue); - $currentValue = rex_escape($currentValue); - } - // diff values for specific fields - if($change === 'changed') { - switch($field->getTypeName()) { - case 'text': - case 'textarea': - $diff = rex_yform_history_helper::diffStringsToHtml($currentValue, $historyValue); - $historyValue = $diff; - break; - - default: - if($historyValue !== $currentValue) { - $historyValue = '' . $historyValue . ''; - } - break; + // diff values for specific fields + if('changed' === $change) { + switch($field->getTypeName()) { + case 'text': + case 'textarea': + $diff = rex_yform_history_helper::diffStringsToHtml($currentValue, $historyValue); + $historyValue = $diff; + break; + + default: + if($historyValue !== $currentValue) { + $historyValue = '' . $historyValue . ''; + } + break; + } } - } - $diffs[$change]['rows'] .= ' + $diffs[$change]['rows'] .= ' '; - // remove field from dataset to collect meanwhile deleted fields - unset($data[$field->getName()]); -} + // remove field from dataset to collect meanwhile deleted fields + unset($data[$field->getName()]); + } foreach ($data as $field => $value) { - $diffs['removed']['count']++; + ++$diffs['removed']['count']; $diffs['removed']['rows'] .= '
' . rex_yform_history_helper::getFieldTypeIcon($field) . ' ' . $field->getLabel() . '' . rex_yform_history_helper::getFieldTypeIcon($field) . ' ' . $field->getLabel() . ' ' . rex_yform_history_helper::getFieldValue($field, $currentDataset, $table) . ' ' . rex_i18n::msg('yform_history_diff_not_yet_existing') . '
' . rex_yform_history_helper::getFieldTypeIcon($field) . ' ' . $field->getLabel() . ' ' . $currentValue . ' ' . $historyValue . '
@@ -163,21 +161,21 @@ foreach ($diffs as $change => $diff) { $content .= ' -
+
' . rex_i18n::msg('yform_history_diff_headline_' . $change) . ' [' . ($diff['count'] > 0 ? '' : '') . $diff['count'] . ($diff['count'] > 0 ? '' : '') . ']' . '
-
'; +
'; - if($diff['rows'] !== '') { - $content .= ' + if('' !== $diff['rows']) { + $content .= ' - + - + ' . $diff['rows'] . ' @@ -190,8 +188,8 @@ $content .= ' @@ -204,4 +202,4 @@ '; echo $content; -endif; \ No newline at end of file +endif; diff --git a/plugins/manager/lib/yform_history_helper.php b/plugins/manager/lib/yform_history_helper.php index eeb478a1c..7fe3edf21 100644 --- a/plugins/manager/lib/yform_history_helper.php +++ b/plugins/manager/lib/yform_history_helper.php @@ -1,6 +1,6 @@ field type icons + */ + public const FIELD_TYPE_ICONS = [ 'question' => 'question', 'checkbox' => 'square-check', @@ -37,23 +40,26 @@ class rex_yform_history_helper 'time' => 'clock', 'upload' => 'upload', 'uuid' => 'key', - 'email' => 'at' + 'email' => 'at', ]; - const FIELD_TYPE_ICON_WEIGHT_CLASS = 'far'; + /** + * @var string field type icons font width class + */ + public const FIELD_TYPE_ICON_WEIGHT_CLASS = 'far'; /** * detect diffs in 2 strings * @param $old * @param $new - * @return array|array[] + * @return array> * @author Peter Schulze | p.schulze[at]bitshifters.de * @created 17.04.2024 * @copyright https://github.com/paulgb/simplediff | Paul Butler (paulgb) */ public static function diffStrings($old, $new): array { - $matrix = array(); + $matrix = []; $maxlen = $omax = $nmax = 0; foreach ($old as $oindex => $ovalue) { @@ -74,14 +80,14 @@ public static function diffStrings($old, $new): array } } - if ($maxlen === 0) { - return array(array('d' => $old, 'i' => $new)); + if (0 === $maxlen) { + return [['d' => $old, 'i' => $new]]; } return array_merge( - rex_yform_history_helper::diffStrings(array_slice($old, 0, $omax), array_slice($new, 0, $nmax)), + self::diffStrings(array_slice($old, 0, $omax), array_slice($new, 0, $nmax)), array_slice($new, $nmax, $maxlen), - rex_yform_history_helper::diffStrings(array_slice($old, $omax + $maxlen), array_slice($new, $nmax + $maxlen)) + self::diffStrings(array_slice($old, $omax + $maxlen), array_slice($new, $nmax + $maxlen)), ); } @@ -102,15 +108,15 @@ public static function diffStringsToHtml($old, $new): string foreach ($diff as $k) { if (is_array($k)) { $ret .= - (isset($k['d']) && count($k['d']) > 0 ? "" . implode(' ', $k['d']) . " " : ''). - (isset($k['i']) && count($k['i']) > 0 ? "" . implode(' ', $k['i']) . " " : '') + (isset($k['d']) && count($k['d']) > 0 ? '' . implode(' ', $k['d']) . ' ' : '') . + (isset($k['i']) && count($k['i']) > 0 ? '' . implode(' ', $k['i']) . ' ' : '') ; } else { $ret .= $k . ' '; } } - return $ret; + return trim($ret); } /** @@ -124,20 +130,20 @@ public static function diffStringsToHtml($old, $new): string * @author Peter Schulze | p.schulze[at]bitshifters.de * @created 22.04.2024 */ - public static function getFieldTypeIcon(rex_yform_manager_field $field, bool $addPrefix = true, bool $outputHtml = true, bool $addTooltip = true, string $tooltipPlacement = 'top'):string + public static function getFieldTypeIcon(rex_yform_manager_field $field, bool $addPrefix = true, bool $outputHtml = true, bool $addTooltip = true, string $tooltipPlacement = 'top'): string { - $icon = rex_yform_history_helper::FIELD_TYPE_ICONS[$field->getTypeName()] ?? 'default'; - $tag = isset(rex_yform_history_helper::FIELD_TYPE_ICONS[$field->getTypeName()]) ? 'i' : 'span'; + $icon = self::FIELD_TYPE_ICONS[$field->getTypeName()] ?? 'default'; + $tag = isset(self::FIELD_TYPE_ICONS[$field->getTypeName()]) ? 'i' : 'span'; - switch($field->getTypeName()) { + switch ($field->getTypeName()) { case 'choice': - $expanded = (bool)(int)$field->getElement('expanded'); - $multiple = (bool)(int)$field->getElement('multiple'); + $expanded = (bool) (int) $field->getElement('expanded'); + $multiple = (bool) (int) $field->getElement('multiple'); - if($expanded && $multiple) { - $icon = rex_yform_history_helper::FIELD_TYPE_ICONS['choice_checkbox']; - } elseif($expanded) { - $icon = rex_yform_history_helper::FIELD_TYPE_ICONS['choice_radio']; + if ($expanded && $multiple) { + $icon = self::FIELD_TYPE_ICONS['choice_checkbox']; + } elseif ($expanded) { + $icon = self::FIELD_TYPE_ICONS['choice_radio']; } break; } @@ -146,8 +152,8 @@ public static function getFieldTypeIcon(rex_yform_manager_field $field, bool $ad $tag . ($addTooltip ? ' data-toggle="tooltip" data-placement="' . $tooltipPlacement . '" title="' . rex_i18n::msg('yform_manager_type_name') . ': ' . $field->getTypeName() . '"' : '') . ' class="' : '' - ). - ($icon !== 'default' ? rex_yform_history_helper::FIELD_TYPE_ICON_WEIGHT_CLASS . ' ' : '').($addPrefix ? 'rex-icon ' : '') . 'fa-' . $icon . + ) . + ('default' !== $icon ? self::FIELD_TYPE_ICON_WEIGHT_CLASS . ' ' : '') . ($addPrefix ? 'rex-icon ' : '') . 'fa-' . $icon . ($outputHtml ? '">' : ''); } @@ -160,22 +166,24 @@ public static function getFieldTypeIcon(rex_yform_manager_field $field, bool $ad * @author Peter Schulze | p.schulze[at]bitshifters.de * @created 22.04.2024 */ - public static function getFieldValue(rex_yform_manager_field $field, rex_yform_manager_dataset $dataset, rex_yform_manager_table $table): string { + public static function getFieldValue(rex_yform_manager_field $field, rex_yform_manager_dataset $dataset, rex_yform_manager_table $table): string + { $class = 'rex_yform_value_' . $field->getTypeName(); $currentValue = ($dataset->hasValue($field->getName()) ? $dataset->getValue($field->getName()) : '-'); - if (is_callable([$class, 'getListValue']) && !in_array($field->getTypeName(), ['text','textarea'], true)) { - /** @var rex_yform_value_abstract $class */ - + if ( + is_callable([$class, 'getListValue']) && + !in_array($field->getTypeName(), ['text','textarea'], true) + ) { // get (formatted) value for current entry - if($dataset->hasValue($field->getName())) { + if ($dataset->hasValue($field->getName())) { $currentValue = $class::getListValue([ 'value' => $currentValue, 'subject' => $currentValue, 'field' => $field->getName(), 'params' => [ 'field' => $field->toArray(), - 'fields' => $table->getFields() + 'fields' => $table->getFields(), ], ]); } else { @@ -187,4 +195,4 @@ public static function getFieldValue(rex_yform_manager_field $field, rex_yform_m return $currentValue; } -} \ No newline at end of file +} diff --git a/plugins/manager/pages/data_history.php b/plugins/manager/pages/data_history.php index f5c9b933a..a8e6fceb2 100644 --- a/plugins/manager/pages/data_history.php +++ b/plugins/manager/pages/data_history.php @@ -194,7 +194,6 @@ $list->addLinkAttribute('view', 'data-toggle', 'modal'); $list->addLinkAttribute('view', 'data-target', '#rex-yform-history-modal'); - $list->addColumn('restore', $restoreColumnBody, -1, ['', $actionsCell]); $list->setColumnParams('restore', ['subfunc' => 'restore', 'data_id' => '###dataset_id###', 'history_id' => '###hid###'] + rex_csrf_token::factory($_csrf_key)->getUrlParams()); $list->addLinkAttribute('restore', 'onclick', 'return confirm(\'' . rex_i18n::msg('yform_history_restore_confirm') . '\');'); @@ -205,8 +204,8 @@ // revision / number $revision = 'revision'; $list->addColumn($revision, '', 2, [ - '', - '' + '', + '', ]); rex::setProperty('YFORM_HISTORY_REVISION', 0); @@ -214,7 +213,7 @@ $list->setColumnFormat( $revision, 'custom', - static function($a) use (&$rev, &$historyDatasets, &$table, &$sql) { + static function ($a) use (&$rev, &$historyDatasets, &$table, &$sql) { // early column ... store all values for current revision $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0); @@ -233,7 +232,7 @@ static function($a) use (&$rev, &$historyDatasets, &$table, &$sql) { $class = 'rex_yform_value_' . $field->getTypeName(); if (!array_key_exists($field->getName(), $data)) { - if(method_exists($class, 'getListValue')) { + if (method_exists($class, 'getListValue')) { $historyDatasets[$rev]['added'][$field->getName()] = $historyDatasets[$rev]['added_current'][$field->getName()] = true; } @@ -251,19 +250,19 @@ static function($a) use (&$rev, &$historyDatasets, &$table, &$sql) { } // compare with prev - if(isset($historyDatasets[$rev - 1])) { + if (isset($historyDatasets[$rev - 1])) { $prev = &$historyDatasets[$rev - 1]; // clean up added - foreach($historyDatasets[$rev]['added'] as $field => $true) { - if(isset($prev['added'][$field])) { + foreach ($historyDatasets[$rev]['added'] as $field => $true) { + if (isset($prev['added'][$field])) { unset($prev['added'][$field]); } } // handle removed - foreach($prev['removed_current'] as $field => $value) { - if(!isset($historyDatasets[$rev]['removed_current'][$field])) { + foreach ($prev['removed_current'] as $field => $value) { + if (!isset($historyDatasets[$rev]['removed_current'][$field])) { $historyDatasets[$rev]['removed'][$field] = $value; } } @@ -272,14 +271,14 @@ static function($a) use (&$rev, &$historyDatasets, &$table, &$sql) { rex::setProperty('YFORM_HISTORY_REVISION', $rev + 1); // dump($historyDatasets); return $rev; - } + }, ); // changes compared to current dataset $changesCurrent = 'changes_to_current'; $list->addColumn($changesCurrent, '', 3, [ - '', - '' + '', + '', ]); $viewColumnLayout = $list->getColumnLayout('view'); @@ -287,7 +286,7 @@ static function($a) use (&$rev, &$historyDatasets, &$table, &$sql) { $list->setColumnFormat( $changesCurrent, 'custom', - static function($a) use (&$dataset, $table, &$historyDatasets, $actionsCell, $normalCell, $changesCurrent) { + static function ($a) use (&$dataset, $table, &$historyDatasets, $actionsCell, $normalCell, $changesCurrent) { $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0) - 1; $changes = 0; @@ -304,13 +303,13 @@ static function($a) use (&$dataset, $table, &$historyDatasets, $actionsCell, $no $historyValue = $historyDataset[$field->getName()]; $currentValue = ($dataset->hasValue($field->getName()) ? $dataset->getValue($field->getName()) : '-'); - if("".$historyValue != "".$currentValue) { - $changes++; + if ('' . $historyValue != '' . $currentValue) { + ++$changes; } } // handle actions column - if($changes == 0) { + if (0 == $changes) { $a['list']->setColumnLayout($changesCurrent, ['', '']); $a['list']->setColumnLayout('view', ['', '']); $a['list']->setColumnLayout('restore', ['', '']); @@ -320,20 +319,20 @@ static function($a) use (&$dataset, $table, &$historyDatasets, $actionsCell, $no $a['list']->setColumnLayout('restore', ['', $actionsCell]); } - return $changes. + return $changes . ($added > 0 || $removed > 0 ? - ' ('.($added > 0 ? '+'.$added.' '.rex_i18n::msg('yform_history_diff_added') : ''). - ($removed > 0 ? ($added > 0 ? ', ' : '').'+'.$removed.' '.rex_i18n::msg('yform_history_diff_removed') : '') - .')' : '' + ' (' . ($added > 0 ? '+' . $added . ' ' . rex_i18n::msg('yform_history_diff_added') : '') . + ($removed > 0 ? ($added > 0 ? ', ' : '') . '+' . $removed . ' ' . rex_i18n::msg('yform_history_diff_removed') : '') + . ')' : '' ); - } + }, ); // changes compared to previous dataset $changesPrev = 'changes_to_prev'; $list->addColumn($changesPrev, '', 4, [ - '', - '' + '', + '', ]); $sql = rex_sql::factory(); @@ -341,7 +340,7 @@ static function($a) use (&$dataset, $table, &$historyDatasets, $actionsCell, $no $list->setColumnFormat( $changesPrev, 'custom', - static function($a) use (&$historyDatasets) { + static function ($a) use (&$historyDatasets) { $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0) - 1; $changes = 0; @@ -350,24 +349,24 @@ static function($a) use (&$historyDatasets) { $historyDataset = &$historyDatasets[$rev]['values']; - if(isset($historyDatasets[$rev - 1])) { + if (isset($historyDatasets[$rev - 1])) { $prevHistoryDataset = $historyDatasets[$rev - 1]['values']; foreach ($historyDataset as $field => $value) { - if("".$historyDataset[$field] != "".$prevHistoryDataset[$field]) { - $changes++; + if ('' . $historyDataset[$field] != '' . $prevHistoryDataset[$field]) { + ++$changes; // dump($rev.": ".$historyDataset[$field]." - ".$prevHistoryDataset[$field]." - ".$changes); } } } - return $changes. + return $changes . ($added > 0 || $removed > 0 ? - ' ('.($added > 0 ? '+'.$added.' '.rex_i18n::msg('yform_history_diff_added') : ''). - ($removed > 0 ? ($added > 0 ? ', ' : '').'+'.$removed.' '.rex_i18n::msg('yform_history_diff_removed') : '') - .')' : '' + ' (' . ($added > 0 ? '+' . $added . ' ' . rex_i18n::msg('yform_history_diff_added') : '') . + ($removed > 0 ? ($added > 0 ? ', ' : '') . '+' . $removed . ' ' . rex_i18n::msg('yform_history_diff_removed') : '') + . ')' : '' ); - } + }, ); $content = $list->get(); @@ -446,7 +445,7 @@ static function($a) use (&$historyDatasets) { $searchForm = $fragment->parse('core/page/section.php'); $fragment = new rex_fragment(); -$fragment->setVar('title', rex_i18n::msg('yform_history_title'). ' '.rex_i18n::msg('yform_history_dataset_id').': '.$datasetId.'', false); +$fragment->setVar('title', rex_i18n::msg('yform_history_title') . ' ' . rex_i18n::msg('yform_history_dataset_id') . ': ' . $datasetId . '', false); $fragment->setVar('options', $options, false); $fragment->setVar('content', $content, false); $searchList = $fragment->parse('core/page/section.php'); From 2fd941aadaf4e514d38a75fd071ac55bf2991f13 Mon Sep 17 00:00:00 2001 From: Peter Schulze Date: Thu, 25 Apr 2024 11:33:03 +0200 Subject: [PATCH 06/11] cs fix --- plugins/manager/lib/yform_history_helper.php | 34 +++++--------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/plugins/manager/lib/yform_history_helper.php b/plugins/manager/lib/yform_history_helper.php index 7fe3edf21..0ac93f96c 100644 --- a/plugins/manager/lib/yform_history_helper.php +++ b/plugins/manager/lib/yform_history_helper.php @@ -9,9 +9,7 @@ */ class rex_yform_history_helper { - /** - * @var array field type icons - */ + /** @var array field type icons */ public const FIELD_TYPE_ICONS = [ 'question' => 'question', @@ -43,15 +41,11 @@ class rex_yform_history_helper 'email' => 'at', ]; - /** - * @var string field type icons font width class - */ + /** @var string field type icons font width class */ public const FIELD_TYPE_ICON_WEIGHT_CLASS = 'far'; /** - * detect diffs in 2 strings - * @param $old - * @param $new + * detect diffs in 2 strings. * @return array> * @author Peter Schulze | p.schulze[at]bitshifters.de * @created 17.04.2024 @@ -92,10 +86,7 @@ public static function diffStrings($old, $new): array } /** - * detect diffs in 2 strings and return as html - * @param $old - * @param $new - * @return string + * detect diffs in 2 strings and return as html. * @author Peter Schulze | p.schulze[at]bitshifters.de * @created 17.04.2024 * @copyright https://github.com/paulgb/simplediff | Paul Butler (paulgb) @@ -103,7 +94,7 @@ public static function diffStrings($old, $new): array public static function diffStringsToHtml($old, $new): string { $ret = ''; - $diff = rex_yform_history_helper::diffStrings(preg_split("/[\s]+/", $old), preg_split("/[\s]+/", $new)); + $diff = self::diffStrings(preg_split('/[\\s]+/', $old), preg_split('/[\\s]+/', $new)); foreach ($diff as $k) { if (is_array($k)) { @@ -120,13 +111,8 @@ public static function diffStringsToHtml($old, $new): string } /** - * get icon for yform field type - * @param rex_yform_manager_field $field - * @param bool $addPrefix + * get icon for yform field type. * @param bool $outputHtml print - * @param bool $addTooltip - * @param string $tooltipPlacement - * @return string * @author Peter Schulze | p.schulze[at]bitshifters.de * @created 22.04.2024 */ @@ -158,11 +144,7 @@ public static function getFieldTypeIcon(rex_yform_manager_field $field, bool $ad } /** - * get field value - * @param rex_yform_manager_field $field - * @param rex_yform_manager_dataset $dataset - * @param rex_yform_manager_table $table - * @return string + * get field value. * @author Peter Schulze | p.schulze[at]bitshifters.de * @created 22.04.2024 */ @@ -173,7 +155,7 @@ public static function getFieldValue(rex_yform_manager_field $field, rex_yform_m if ( is_callable([$class, 'getListValue']) && - !in_array($field->getTypeName(), ['text','textarea'], true) + !in_array($field->getTypeName(), ['text', 'textarea'], true) ) { // get (formatted) value for current entry if ($dataset->hasValue($field->getName())) { From a3238f322629db23127ae05465bfafc81ef9abbc Mon Sep 17 00:00:00 2001 From: Peter Schulze Date: Thu, 25 Apr 2024 12:32:08 +0200 Subject: [PATCH 07/11] rex stan: next round ... --- .../manager/fragments/yform/manager/history.diff.php | 2 +- plugins/manager/lib/yform_history_helper.php | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/plugins/manager/fragments/yform/manager/history.diff.php b/plugins/manager/fragments/yform/manager/history.diff.php index 4ef878c88..e606b1a80 100644 --- a/plugins/manager/fragments/yform/manager/history.diff.php +++ b/plugins/manager/fragments/yform/manager/history.diff.php @@ -9,7 +9,7 @@ $datasetId = $this->getVar('dataset_id', null); $currentDataset = $this->getVar('current_dataset', null); -/** @var rex_yform_manager_table $table */ +/** @var rex_yform_manager_table|null $table */ $table = $this->getVar('table', null); $sql = rex_sql::factory(); diff --git a/plugins/manager/lib/yform_history_helper.php b/plugins/manager/lib/yform_history_helper.php index 0ac93f96c..11d85feeb 100644 --- a/plugins/manager/lib/yform_history_helper.php +++ b/plugins/manager/lib/yform_history_helper.php @@ -10,7 +10,7 @@ class rex_yform_history_helper { /** @var array field type icons */ - public const FIELD_TYPE_ICONS = [ + private const FIELD_TYPE_ICONS = [ 'question' => 'question', 'checkbox' => 'square-check', @@ -42,7 +42,7 @@ class rex_yform_history_helper ]; /** @var string field type icons font width class */ - public const FIELD_TYPE_ICON_WEIGHT_CLASS = 'far'; + private const FIELD_TYPE_ICON_WEIGHT_CLASS = 'far'; /** * detect diffs in 2 strings. @@ -50,6 +50,7 @@ class rex_yform_history_helper * @author Peter Schulze | p.schulze[at]bitshifters.de * @created 17.04.2024 * @copyright https://github.com/paulgb/simplediff | Paul Butler (paulgb) + * @api */ public static function diffStrings($old, $new): array { @@ -90,6 +91,7 @@ public static function diffStrings($old, $new): array * @author Peter Schulze | p.schulze[at]bitshifters.de * @created 17.04.2024 * @copyright https://github.com/paulgb/simplediff | Paul Butler (paulgb) + * @api */ public static function diffStringsToHtml($old, $new): string { @@ -99,8 +101,8 @@ public static function diffStringsToHtml($old, $new): string foreach ($diff as $k) { if (is_array($k)) { $ret .= - (isset($k['d']) && count($k['d']) > 0 ? '' . implode(' ', $k['d']) . ' ' : '') . - (isset($k['i']) && count($k['i']) > 0 ? '' . implode(' ', $k['i']) . ' ' : '') + (isset($k['d']) && is_array($k['d']) && count($k['d']) > 0 ? '' . implode(' ', $k['d']) . ' ' : '') . + (isset($k['i']) && is_array($k['i']) && count($k['i']) > 0 ? '' . implode(' ', $k['i']) . ' ' : '') ; } else { $ret .= $k . ' '; From b8f423dd826c44f13ddf42c52d22c22e59af79ba Mon Sep 17 00:00:00 2001 From: Peter Schulze Date: Sun, 28 Apr 2024 17:17:07 +0200 Subject: [PATCH 08/11] warning and less table columns if reference dataset_id is missing or does not result in an existing dataset rex stan: more fixes --- plugins/manager/lang/de_de.lang | 1 + plugins/manager/lang/en_gb.lang | 1 + plugins/manager/lang/es_es.lang | 1 + plugins/manager/lang/sv_se.lang | 1 + plugins/manager/pages/data_history.php | 155 ++++++++++++++----------- 5 files changed, 90 insertions(+), 69 deletions(-) diff --git a/plugins/manager/lang/de_de.lang b/plugins/manager/lang/de_de.lang index 7cc4fc89b..9ba9c5245 100644 --- a/plugins/manager/lang/de_de.lang +++ b/plugins/manager/lang/de_de.lang @@ -255,6 +255,7 @@ yform_history_delete_older_3_months = älter als 3 Monate yform_history_delete_confirm = Historie wirklich löschen? yform_history_delete_success = Die Historien-Datensätze wurden gelöscht. yform_history_revision = Revision/Änderung +yform_history_dataset_missing = Es wurde keine (gültige) Datensatz-ID übergeben! Der Vergleich mit einem ausgewählten Eintrag der Historie ist daher nicht möglich. yform_history_diff_headline_changed = Geänderte Werte yform_history_diff_headline_unchanged = Unveränderte Werte yform_history_diff_headline_added = Hinzugefügte Felder diff --git a/plugins/manager/lang/en_gb.lang b/plugins/manager/lang/en_gb.lang index a65920aed..56a421889 100644 --- a/plugins/manager/lang/en_gb.lang +++ b/plugins/manager/lang/en_gb.lang @@ -255,6 +255,7 @@ yform_history_delete_older_3_months = older than 3 months yform_history_delete_confirm = Delete History? yform_history_delete_success = History records deleted. yform_history_revision = revision/change +yform_history_dataset_missing = No (valid) data record ID was transferred! A comparison with a selected entry in the history is therefore not possible. yform_history_diff_headline_changed = changed values yform_history_diff_headline_unchanged = unchanged values yform_history_diff_headline_added = added fields diff --git a/plugins/manager/lang/es_es.lang b/plugins/manager/lang/es_es.lang index d983bf670..29c0542a1 100644 --- a/plugins/manager/lang/es_es.lang +++ b/plugins/manager/lang/es_es.lang @@ -255,6 +255,7 @@ yform_history_delete_older_3_months = Más de 3 meses yform_history_delete_confirm = ¿Realmente borras la historia? yform_history_delete_success = Los registros de historial han sido eliminados. yform_history_revision = Revisión/modificación +yform_history_dataset_missing = No se ha transferido ningún ID de registro de datos (válido). Por lo tanto, no es posible realizar una comparación con una entrada seleccionada en el historial. yform_history_diff_headline_changed = Valores modificados yform_history_diff_headline_unchanged = Valores sin cambios yform_history_diff_headline_added = Campos añadidos diff --git a/plugins/manager/lang/sv_se.lang b/plugins/manager/lang/sv_se.lang index 1b780c478..6e5b575b2 100644 --- a/plugins/manager/lang/sv_se.lang +++ b/plugins/manager/lang/sv_se.lang @@ -255,6 +255,7 @@ yform_history_delete_older_3_months = äldre än 3 månader yform_history_delete_confirm = Vill du verkligen radera historiken? yform_history_delete_success = Poster från historiken raderades. yform_history_revision = Revision/Förändring +yform_history_dataset_missing = Inget (giltigt) datapost-ID har överförts! En jämförelse med en vald post i historiken är därför inte möjlig. yform_history_diff_headline_changed = Ändrade Värden yform_history_diff_headline_unchanged = Oförändrade Värden yform_history_diff_headline_added = Tillagda Fält diff --git a/plugins/manager/pages/data_history.php b/plugins/manager/pages/data_history.php index a8e6fceb2..5bf790e15 100644 --- a/plugins/manager/pages/data_history.php +++ b/plugins/manager/pages/data_history.php @@ -16,23 +16,24 @@ $table = $this->table; $dataset = null; -if ($datasetId) { +$filterWhere = ''; + +if (null !== $datasetId && $datasetId > 0) { $dataset = rex_yform_manager_dataset::getRaw($datasetId, $table->getTableName()); + + if ($filterDataset) { + // echo rex_view::info('' . rex_i18n::msg('yform_history_dataset_id') . ': ' . $datasetId); + $filterWhere = ' AND dataset_id = ' . $datasetId; + } } else { $filterDataset = false; } -$filterWhere = ''; -if ($filterDataset) { - // echo rex_view::info('' . rex_i18n::msg('yform_history_dataset_id') . ': ' . $datasetId); - $filterWhere = ' AND dataset_id = ' . $datasetId; -} - -if ($historySearchId) { +if (null !== $historySearchId) { $filterWhere .= ' AND dataset_id = ' . $historySearchId; } -if ($historySearchDate) { +if (null !== $historySearchDate) { $historyDateObject = DateTime::createFromFormat('Y-m-d', $historySearchDate); if (!$historyDateObject) { $historyDateObject = new DateTime(); @@ -41,15 +42,15 @@ $filterWhere .= ' AND timestamp <= ' . rex_sql::factory()->escape($historyDateObject->format('Y-m-d')); } -if ($historySearchUser) { +if (null !== $historySearchUser) { $filterWhere .= ' AND user =' . rex_sql::factory()->escape($historySearchUser); } -if ($historySearchAction) { +if (null !== $historySearchAction) { $filterWhere .= ' AND action =' . rex_sql::factory()->escape($historySearchAction); } -if ('view' === $subfunc && $dataset && $historyId) { +if ('view' === $subfunc && null !== $dataset && $historyId > 0) { $historyDiff = new rex_fragment(); $historyDiff->setVar('history_id', $historyId); $historyDiff->setVar('dataset_id', $datasetId); @@ -61,7 +62,7 @@ exit; } -if ('restore' === $subfunc && $dataset && $historyId) { +if ('restore' === $subfunc && null !== $dataset && $historyId > 0) { if ($dataset->restoreSnapshot($historyId)) { echo rex_view::success(rex_i18n::msg('yform_history_restore_success')); } else { @@ -128,22 +129,25 @@ if ($filterDataset) { $list->addParam('filter_dataset', 1); - $list->addParam('data_id', $datasetId); + + if (null !== $datasetId && $datasetId > 0) { + $list->addParam('data_id', $datasetId); + } } -if ($historySearchId) { +if (null !== $historySearchId) { $list->addParam('historySearchId', $historySearchId); } -if ($historySearchDate) { +if (null !== $historySearchDate) { $list->addParam('historySearchDate', $historySearchDate); } -if ($historySearchUser) { +if (null !== $historySearchUser) { $list->addParam('historySearchUser', $historySearchUser); } -if ($historySearchAction) { +if (null !== $historySearchAction) { $list->addParam('historySearchAction', $historySearchAction); } @@ -189,7 +193,10 @@ $actionsCell = ''; $normalCell = ''; -$list->addColumn('view', $viewColumnBody, -1, ['', $actionsCell]); +if (null !== $dataset) { + $list->addColumn('view', $viewColumnBody, -1, ['', $actionsCell]); +} + $list->setColumnParams('view', ['subfunc' => 'view', 'data_id' => '###dataset_id###', 'history_id' => '###hid###']); $list->addLinkAttribute('view', 'data-toggle', 'modal'); $list->addLinkAttribute('view', 'data-target', '#rex-yform-history-modal'); @@ -225,7 +232,7 @@ static function ($a) use (&$rev, &$historyDatasets, &$table, &$sql) { 'removed_current' => [], ]; - $data = $sql->getArray(sprintf('SELECT * FROM %s WHERE history_id = %d', rex::getTable('yform_history_field'), $a['list']->getValue('hid'))); + $data = $sql->getArray(sprintf('SELECT * FROM %s WHERE history_id = :id', rex::getTable('yform_history_field')), [':id' => $a['list']->getValue('hid')]); $data = array_column($data, 'value', 'field'); foreach ($table->getValueFields() as $field) { @@ -275,58 +282,60 @@ static function ($a) use (&$rev, &$historyDatasets, &$table, &$sql) { ); // changes compared to current dataset -$changesCurrent = 'changes_to_current'; -$list->addColumn($changesCurrent, '', 3, [ - '', - '', -]); +if (null !== $dataset) { + $changesCurrent = 'changes_to_current'; + $list->addColumn($changesCurrent, '', 3, [ + '', + '', + ]); -$viewColumnLayout = $list->getColumnLayout('view'); + $viewColumnLayout = $list->getColumnLayout('view'); -$list->setColumnFormat( - $changesCurrent, - 'custom', - static function ($a) use (&$dataset, $table, &$historyDatasets, $actionsCell, $normalCell, $changesCurrent) { - $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0) - 1; + $list->setColumnFormat( + $changesCurrent, + 'custom', + static function ($a) use (&$dataset, $table, &$historyDatasets, $actionsCell, $normalCell, $changesCurrent) { + $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0) - 1; - $changes = 0; - $added = count($historyDatasets[$rev]['added_current']); - $removed = count($historyDatasets[$rev]['removed_current']); + $changes = 0; + $added = count($historyDatasets[$rev]['added_current']); + $removed = count($historyDatasets[$rev]['removed_current']); - $historyDataset = &$historyDatasets[$rev]['values']; + $historyDataset = &$historyDatasets[$rev]['values']; - foreach ($table->getValueFields() as $field) { - if (!array_key_exists($field->getName(), $historyDataset)) { - continue; - } + foreach ($table->getValueFields() as $field) { + if (!array_key_exists($field->getName(), $historyDataset)) { + continue; + } - $historyValue = $historyDataset[$field->getName()]; - $currentValue = ($dataset->hasValue($field->getName()) ? $dataset->getValue($field->getName()) : '-'); + $historyValue = $historyDataset[$field->getName()]; + $currentValue = ($dataset->hasValue($field->getName()) ? $dataset->getValue($field->getName()) : '-'); - if ('' . $historyValue != '' . $currentValue) { - ++$changes; + if ('' . $historyValue !== '' . $currentValue) { + ++$changes; + } } - } - // handle actions column - if (0 == $changes) { - $a['list']->setColumnLayout($changesCurrent, ['', '']); - $a['list']->setColumnLayout('view', ['', '']); - $a['list']->setColumnLayout('restore', ['', '']); - } else { - $a['list']->setColumnLayout($changesCurrent, ['', $normalCell]); - $a['list']->setColumnLayout('view', ['', $actionsCell]); - $a['list']->setColumnLayout('restore', ['', $actionsCell]); - } + // handle actions column + if (0 === $changes) { + $a['list']->setColumnLayout($changesCurrent, ['', '']); + $a['list']->setColumnLayout('view', ['', '']); + $a['list']->setColumnLayout('restore', ['', '']); + } else { + $a['list']->setColumnLayout($changesCurrent, ['', $normalCell]); + $a['list']->setColumnLayout('view', ['', $actionsCell]); + $a['list']->setColumnLayout('restore', ['', $actionsCell]); + } - return $changes . - ($added > 0 || $removed > 0 ? - ' (' . ($added > 0 ? '+' . $added . ' ' . rex_i18n::msg('yform_history_diff_added') : '') . - ($removed > 0 ? ($added > 0 ? ', ' : '') . '+' . $removed . ' ' . rex_i18n::msg('yform_history_diff_removed') : '') - . ')' : '' - ); - }, -); + return $changes . + ($added > 0 || $removed > 0 ? + ' (' . ($added > 0 ? '+' . $added . ' ' . rex_i18n::msg('yform_history_diff_added') : '') . + ($removed > 0 ? ($added > 0 ? ', ' : '') . '+' . $removed . ' ' . rex_i18n::msg('yform_history_diff_removed') : '') + . ')' : '' + ); + }, + ); +} // changes compared to previous dataset $changesPrev = 'changes_to_prev'; @@ -353,7 +362,7 @@ static function ($a) use (&$historyDatasets) { $prevHistoryDataset = $historyDatasets[$rev - 1]['values']; foreach ($historyDataset as $field => $value) { - if ('' . $historyDataset[$field] != '' . $prevHistoryDataset[$field]) { + if ('' . $historyDataset[$field] !== '' . $prevHistoryDataset[$field]) { ++$changes; // dump($rev.": ".$historyDataset[$field]." - ".$prevHistoryDataset[$field]." - ".$changes); } @@ -361,11 +370,11 @@ static function ($a) use (&$historyDatasets) { } return $changes . - ($added > 0 || $removed > 0 ? - ' (' . ($added > 0 ? '+' . $added . ' ' . rex_i18n::msg('yform_history_diff_added') : '') . - ($removed > 0 ? ($added > 0 ? ', ' : '') . '+' . $removed . ' ' . rex_i18n::msg('yform_history_diff_removed') : '') - . ')' : '' - ); + ($added > 0 || $removed > 0 ? + ' (' . ($added > 0 ? '+' . $added . ' ' . rex_i18n::msg('yform_history_diff_added') : '') . + ($removed > 0 ? ($added > 0 ? ', ' : '') . '+' . $removed . ' ' . rex_i18n::msg('yform_history_diff_removed') : '') + . ')' : '' + ); }, ); @@ -403,7 +412,7 @@ static function ($a) use (&$historyDatasets) { $historySearchForm->setObjectparams('csrf_protection', false); $historySearchForm->setHiddenField('_csrf_token', rex_csrf_token::factory($_csrf_key)->getValue()); -if (!$datasetId) { +if (null !== $datasetId && $datasetId > 0) { $historySearchForm->setValueField('text', [ 'name' => 'historySearchId', 'label' => 'id', @@ -438,6 +447,10 @@ static function ($a) use (&$historyDatasets) { ), ]); +if (null !== $dataset) { + $noDatasetWarning = \rex_view::warning(rex_i18n::msg('yform_history_dataset_missing')); +} + $fragment = new rex_fragment(); $fragment->setVar('class', 'edit', false); $fragment->setVar('title', rex_i18n::msg('yform_manager_search')); @@ -450,6 +463,10 @@ static function ($a) use (&$historyDatasets) { $fragment->setVar('content', $content, false); $searchList = $fragment->parse('core/page/section.php'); +if (null === $dataset) { + echo rex_view::warning(rex_i18n::msg('yform_history_dataset_missing')); +} + echo '
'; echo '
' . $searchForm . '
'; echo '
' . $searchList . '
'; From e6eda593abcf8b99034130112bcfef23c760c597 Mon Sep 17 00:00:00 2001 From: Peter Schulze Date: Tue, 11 Jun 2024 17:04:06 +0200 Subject: [PATCH 09/11] overlooked general history (for whole table, not a single dataset): now old history is present when table history is opened and new more functional history on dataset specific history + bringing back search + marker for current dataset in dataset specific mode + added css + outsourced js --- plugins/manager/assets/history.js | 14 + plugins/manager/assets/manager.css | 121 ++++++++ plugins/manager/boot.php | 1 + .../fragments/yform/manager/history.diff.php | 10 +- plugins/manager/lang/de_de.lang | 1 + plugins/manager/lang/en_gb.lang | 1 + plugins/manager/lang/es_es.lang | 1 + plugins/manager/lang/sv_se.lang | 1 + plugins/manager/lib/yform/manager/dataset.php | 2 +- plugins/manager/lib/yform_history_helper.php | 2 +- plugins/manager/pages/data_history.php | 274 +++++++++--------- 11 files changed, 289 insertions(+), 139 deletions(-) create mode 100644 plugins/manager/assets/history.js diff --git a/plugins/manager/assets/history.js b/plugins/manager/assets/history.js new file mode 100644 index 000000000..6385bfa60 --- /dev/null +++ b/plugins/manager/assets/history.js @@ -0,0 +1,14 @@ + +$(document).on('rex:ready', function (event, container) { + container.find('#rex-yform-history-modal').on('shown.bs.modal', function () { + // init tooltips + container.find('[data-toggle="tooltip"]').tooltip({ + html: true + }); + + // history restore confirm dialog + $("#yform-manager-history-restore").on("click", function() { + return confirm($(this).attr('data-confirm-text')); + }); + }); +}); \ No newline at end of file diff --git a/plugins/manager/assets/manager.css b/plugins/manager/assets/manager.css index 6dd26e921..c3e475cb2 100644 --- a/plugins/manager/assets/manager.css +++ b/plugins/manager/assets/manager.css @@ -287,3 +287,124 @@ body.rex-theme-dark .yform-be-relation-wrapper > div { background: #1a3332 } } + +#rex-yform-history-modal.in { + display: flex !important; +} + +#rex-yform-history-modal header.panel-heading:not(:first-of-type) { + margin-top: 3px; +} + +#rex-yform-history-modal header.panel-heading .panel-title i { + display: inline-block; + width: 25px; +} + +#rex-yform-history-modal header + .panel-collapse { + padding-top: 5px; +} + +.history-list tr.current-dataset-row { + background-color: #a0e4c1; +} + +.history-list .current-dataset-cell { + text-align: center; +} + +.history-list .current-dataset-hint { + color: #5bb585; + font-style: italic; +} + +.history-diff-table tbody td { + line-height: 1.5 +} + +.history-diff-table ins, +.history-diff-table .diff { + padding: 1px 4px; + border-radius: 3px; +} + +.history-diff-table del { + color: #d68787; +} + +.history-diff-table ins { + background-color: #a6e1a6; + text-decoration: none; +} + +.history-diff-table .diff { + background-color: #c6daff; +} + +.history-diff-table thead th:first-child { + padding-left: 10px; +} + +.history-diff-table tbody th:first-child { + padding-left: 45px; + position: relative; +} + +.history-diff-table tbody th:first-child > i, +.history-diff-table tbody th:first-child > span { + display: flex; + background-color: #F5F5F5; + width: 35px; + text-align: left; + position: absolute; + left: 0; + top: 1px; + bottom: 1px; + justify-content: center; + padding-top: 12px; + color: #000; +} + +/* special for numbers */ +.history-diff-table tbody th:first-child > i.rex-icon.fa-1:before { + content: '123'; +} + +.history-diff-table tbody th:first-child > span:before { + content: ''; + display: block; + width: 23px; + height: 14px; + border: 1px solid #000; + border-radius: 3px; +} + +.history-diff-table tbody th:first-child > span:after { + content: 'abc'; + font-size: 8px; + position: absolute; + top: 15px; + left: 9px; + font-weight: bold; +} + +#collapse-history-table-added .history-diff-table tbody th:first-child { + color: #088808; +} + +#collapse-history-table-removed .history-diff-table tbody th:first-child { + color: #e30d0d; +} + +#collapse-history-table-added .history-diff-table tbody td em, +#collapse-history-table-removed .history-diff-table tbody td em { + color: #AAA; +} + +@media (min-width: 768px) { + #rex-yform-history-modal.in .modal-dialog { + max-width: calc(100% - 40px); + width: auto; + display: inline-block; + } +} diff --git a/plugins/manager/boot.php b/plugins/manager/boot.php index 670fa77b7..bd7944829 100644 --- a/plugins/manager/boot.php +++ b/plugins/manager/boot.php @@ -30,6 +30,7 @@ rex_view::addJsFile($this->getAssetsUrl('relations.js')); rex_view::addCssFile($this->getAssetsUrl('manager.css')); rex_view::addJsFile($this->getAssetsUrl('widget.js')); + rex_view::addJsFile($this->getAssetsUrl('history.js')); if (!rex::getUser()->isAdmin()) { $page = $this->getProperty('page'); diff --git a/plugins/manager/fragments/yform/manager/history.diff.php b/plugins/manager/fragments/yform/manager/history.diff.php index e606b1a80..20b08d36f 100644 --- a/plugins/manager/fragments/yform/manager/history.diff.php +++ b/plugins/manager/fragments/yform/manager/history.diff.php @@ -57,7 +57,7 @@ // count diffs if(!$currentDataset->hasValue($field->getName())) { - $change = 'deleted'; + $change = 'removed'; } elseif('' . $historyValue !== '' . $currentValue) { $change = 'changed'; } @@ -188,17 +188,11 @@ $content .= '
- '; echo $content; diff --git a/plugins/manager/lang/de_de.lang b/plugins/manager/lang/de_de.lang index 008f26145..11bf904ce 100644 --- a/plugins/manager/lang/de_de.lang +++ b/plugins/manager/lang/de_de.lang @@ -270,6 +270,7 @@ yform_history_diff_added = neu yform_history_diff_removed = entfernt yform_history_diff_not_yet_existing = noch nicht vorhanden yform_history_diff_no_longer_existing = nicht mehr vorhanden +yform_history_is_current_dataset = aktuelle Version des Datensatzes yform_manager_show_form_notation = Formular-Code diff --git a/plugins/manager/lang/en_gb.lang b/plugins/manager/lang/en_gb.lang index 002673cce..870454727 100644 --- a/plugins/manager/lang/en_gb.lang +++ b/plugins/manager/lang/en_gb.lang @@ -270,6 +270,7 @@ yform_history_diff_added = added yform_history_diff_removed = removed yform_history_diff_not_yet_existing = not yet existing yform_history_diff_no_longer_existing = no longer existing +yform_history_is_current_dataset = current version of the record yform_manager_show_form_notation = Form code diff --git a/plugins/manager/lang/es_es.lang b/plugins/manager/lang/es_es.lang index 29c0542a1..a30ba4c73 100644 --- a/plugins/manager/lang/es_es.lang +++ b/plugins/manager/lang/es_es.lang @@ -267,6 +267,7 @@ yform_history_diff_added = nuevo yform_history_diff_removed = eliminado yform_history_diff_not_yet_existing = aún no disponible yform_history_diff_no_longer_existing = ya no está disponible +yform_history_is_current_dataset = versión actual del registro. yform_manager_show_form_notation = Código del formulario diff --git a/plugins/manager/lang/sv_se.lang b/plugins/manager/lang/sv_se.lang index 6e5b575b2..ca834cf70 100644 --- a/plugins/manager/lang/sv_se.lang +++ b/plugins/manager/lang/sv_se.lang @@ -267,6 +267,7 @@ yform_history_diff_added = Tillagd yform_history_diff_removed = Borttagen yform_history_diff_not_yet_existing = Ännu Inte Existerande yform_history_diff_no_longer_existing = Inte Längre Existerande +yform_history_is_current_dataset = aktuella versionen av datasatsen yform_manager_show_form_notation = Formularkod diff --git a/plugins/manager/lib/yform/manager/dataset.php b/plugins/manager/lib/yform/manager/dataset.php index aca1e6233..c28d21abd 100644 --- a/plugins/manager/lib/yform/manager/dataset.php +++ b/plugins/manager/lib/yform/manager/dataset.php @@ -743,7 +743,7 @@ private static function tableToModel(string $table): string /** * @internal */ - protected static function modelToTable(): string + final protected static function modelToTable(): string { $class = static::class; diff --git a/plugins/manager/lib/yform_history_helper.php b/plugins/manager/lib/yform_history_helper.php index 11d85feeb..2e5d9471a 100644 --- a/plugins/manager/lib/yform_history_helper.php +++ b/plugins/manager/lib/yform_history_helper.php @@ -46,7 +46,7 @@ class rex_yform_history_helper /** * detect diffs in 2 strings. - * @return array> + * @return array * @author Peter Schulze | p.schulze[at]bitshifters.de * @created 17.04.2024 * @copyright https://github.com/paulgb/simplediff | Paul Butler (paulgb) diff --git a/plugins/manager/pages/data_history.php b/plugins/manager/pages/data_history.php index 5bf790e15..0eff6e4bb 100644 --- a/plugins/manager/pages/data_history.php +++ b/plugins/manager/pages/data_history.php @@ -3,22 +3,22 @@ /** @var rex_yform_manager $this */ $subfunc = rex_request('subfunc', 'string'); -$datasetId = rex_request('data_id', 'int', null); +$datasetId = rex_request('data_id', 'int', 0); $filterDataset = rex_request('filter_dataset', 'bool'); $historyId = rex_request('history_id', 'int'); $_csrf_key ??= ''; -$historySearchId = rex_request('historySearchId', 'int', null); -$historySearchDate = rex_request('historySearchDate', 'string', null); -$historySearchUser = rex_request('historySearchUser', 'string', null); -$historySearchAction = rex_request('historySearchAction', 'string', null); +$historySearchId = rex_request('historySearchId', 'int', 0); +$historySearchDate = trim(rex_request('historySearchDate', 'string', '')); +$historySearchUser = trim(rex_request('historySearchUser', 'string', '')); +$historySearchAction = trim(rex_request('historySearchAction', 'string', '')); $table = $this->table; $dataset = null; $filterWhere = ''; -if (null !== $datasetId && $datasetId > 0) { +if ($datasetId > 0) { $dataset = rex_yform_manager_dataset::getRaw($datasetId, $table->getTableName()); if ($filterDataset) { @@ -29,28 +29,33 @@ $filterDataset = false; } -if (null !== $historySearchId) { +// detailed dataset history +$isDatasetHistory = null !== $dataset && $dataset->exists() && $datasetId > 0; + +if ($historySearchId > 0 && !$isDatasetHistory) { $filterWhere .= ' AND dataset_id = ' . $historySearchId; } -if (null !== $historySearchDate) { +if ('' !== $historySearchDate) { $historyDateObject = DateTime::createFromFormat('Y-m-d', $historySearchDate); + if (!$historyDateObject) { $historyDateObject = new DateTime(); } + $historyDateObject->modify('+1 day'); - $filterWhere .= ' AND timestamp <= ' . rex_sql::factory()->escape($historyDateObject->format('Y-m-d')); + $filterWhere .= ' AND timestamp < ' . rex_sql::factory()->escape($historyDateObject->format('Y-m-d')); } -if (null !== $historySearchUser) { +if ('' !== $historySearchUser) { $filterWhere .= ' AND user =' . rex_sql::factory()->escape($historySearchUser); } -if (null !== $historySearchAction) { +if ('' !== $historySearchAction) { $filterWhere .= ' AND action =' . rex_sql::factory()->escape($historySearchAction); } -if ('view' === $subfunc && null !== $dataset && $historyId > 0) { +if ('view' === $subfunc && $isDatasetHistory) { $historyDiff = new rex_fragment(); $historyDiff->setVar('history_id', $historyId); $historyDiff->setVar('dataset_id', $datasetId); @@ -62,7 +67,7 @@ exit; } -if ('restore' === $subfunc && null !== $dataset && $historyId > 0) { +if ('restore' === $subfunc && $isDatasetHistory) { if ($dataset->restoreSnapshot($historyId)) { echo rex_view::success(rex_i18n::msg('yform_history_restore_success')); } else { @@ -78,6 +83,7 @@ if (rex::getUser()->isAdmin() && in_array($subfunc, ['delete_old', 'delete_all'], true)) { $where = $filterWhere; + if ('delete_old' === $subfunc) { $where = ' AND h.`timestamp` < DATE_SUB(NOW(), INTERVAL 3 MONTH)'; } @@ -98,9 +104,10 @@ $sql = rex_sql::factory(); -$listQuery = 'SELECT - dataset_id, +$listQuery = ' + SELECT h.id as hid, + dataset_id, id as title, `action`, `user`, `timestamp` FROM ' . rex::getTable('yform_history') . ' h @@ -108,7 +115,8 @@ `table_name` = ' . $sql->escape($table->getTableName()) . $filterWhere; -$userQuery = 'SELECT +$userQuery = ' + SELECT distinct `user` FROM ' . rex::getTable('yform_history') . ' h WHERE @@ -130,30 +138,30 @@ if ($filterDataset) { $list->addParam('filter_dataset', 1); - if (null !== $datasetId && $datasetId > 0) { + if (null !== $dataset && $dataset->exists() && $datasetId > 0) { $list->addParam('data_id', $datasetId); } } -if (null !== $historySearchId) { +if ($historySearchId > 0) { $list->addParam('historySearchId', $historySearchId); } -if (null !== $historySearchDate) { +if ('' !== $historySearchDate) { $list->addParam('historySearchDate', $historySearchDate); } -if (null !== $historySearchUser) { +if ('' !== $historySearchUser) { $list->addParam('historySearchUser', $historySearchUser); } -if (null !== $historySearchAction) { +if ('' !== $historySearchAction) { $list->addParam('historySearchAction', $historySearchAction); } $list->removeColumn('id'); -$list->removeColumn('dataset_id'); +$list->setColumnLabel('hid', rex_i18n::msg('yform_id')); $list->setColumnLabel('dataset_id', rex_i18n::msg('yform_history_dataset_id')); $list->setColumnLabel('title', rex_i18n::msg('yform_history_dataset')); $list->setColumnFormat('title', 'custom', static function (array $params) { @@ -193,13 +201,15 @@ $actionsCell = ''; $normalCell = ''; -if (null !== $dataset) { +if ($isDatasetHistory) { + // dataset column already in header, so not necessary to have it in the list + $list->removeColumn('dataset_id'); $list->addColumn('view', $viewColumnBody, -1, ['', $actionsCell]); -} -$list->setColumnParams('view', ['subfunc' => 'view', 'data_id' => '###dataset_id###', 'history_id' => '###hid###']); -$list->addLinkAttribute('view', 'data-toggle', 'modal'); -$list->addLinkAttribute('view', 'data-target', '#rex-yform-history-modal'); + $list->setColumnParams('view', ['subfunc' => 'view', 'data_id' => '###dataset_id###', 'history_id' => '###hid###']); + $list->addLinkAttribute('view', 'data-toggle', 'modal'); + $list->addLinkAttribute('view', 'data-target', '#rex-yform-history-modal'); +} $list->addColumn('restore', $restoreColumnBody, -1, ['', $actionsCell]); $list->setColumnParams('restore', ['subfunc' => 'restore', 'data_id' => '###dataset_id###', 'history_id' => '###hid###'] + rex_csrf_token::factory($_csrf_key)->getUrlParams()); @@ -208,81 +218,82 @@ $historyDatasets = []; $sql = rex_sql::factory(); -// revision / number -$revision = 'revision'; -$list->addColumn($revision, '', 2, [ - '', - '', -]); +// when showing history of specific dataset +if ($isDatasetHistory) { + // revision / number + $revision = 'revision'; + $list->addColumn($revision, '', 2, [ + '', + '', + ]); -rex::setProperty('YFORM_HISTORY_REVISION', 0); + rex::setProperty('YFORM_HISTORY_REVISION', 0); -$list->setColumnFormat( - $revision, - 'custom', - static function ($a) use (&$rev, &$historyDatasets, &$table, &$sql) { - // early column ... store all values for current revision - $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0); + $list->setColumnFormat( + $revision, + 'custom', + static function ($a) use (&$rev, &$historyDatasets, &$table, &$sql) { + // early column ... store all values for current revision + $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0); + + $historyDatasets[$rev] = [ + 'values' => [], + 'added' => [], + 'added_current' => [], + 'removed' => [], + 'removed_current' => [], + ]; - $historyDatasets[$rev] = [ - 'values' => [], - 'added' => [], - 'added_current' => [], - 'removed' => [], - 'removed_current' => [], - ]; + $data = $sql->getArray(sprintf('SELECT * FROM %s WHERE history_id = :id', rex::getTable('yform_history_field')), [':id' => $a['list']->getValue('hid')]); + $data = array_column($data, 'value', 'field'); - $data = $sql->getArray(sprintf('SELECT * FROM %s WHERE history_id = :id', rex::getTable('yform_history_field')), [':id' => $a['list']->getValue('hid')]); - $data = array_column($data, 'value', 'field'); + foreach ($table->getValueFields() as $field) { + $class = 'rex_yform_value_' . $field->getTypeName(); - foreach ($table->getValueFields() as $field) { - $class = 'rex_yform_value_' . $field->getTypeName(); + if (!array_key_exists($field->getName(), $data)) { + if (method_exists($class, 'getListValue')) { + $historyDatasets[$rev]['added'][$field->getName()] = $historyDatasets[$rev]['added_current'][$field->getName()] = true; + } - if (!array_key_exists($field->getName(), $data)) { - if (method_exists($class, 'getListValue')) { - $historyDatasets[$rev]['added'][$field->getName()] = $historyDatasets[$rev]['added_current'][$field->getName()] = true; + continue; } - continue; + // set data + $historyDatasets[$rev]['values'][$field->getName()] = $data[$field->getName()]; + unset($data[$field->getName()]); } - // set data - $historyDatasets[$rev]['values'][$field->getName()] = $data[$field->getName()]; - unset($data[$field->getName()]); - } - - // check for deleted fields in historic data - foreach ($data as $field => $value) { - $historyDatasets[$rev]['removed_current'][$field] = $value; - } + // check for deleted fields in historic data + foreach ($data as $field => $value) { + $historyDatasets[$rev]['removed_current'][$field] = $value; + } - // compare with prev - if (isset($historyDatasets[$rev - 1])) { - $prev = &$historyDatasets[$rev - 1]; + // compare with prev + if (isset($historyDatasets[$rev - 1])) { + $prev = &$historyDatasets[$rev - 1]; - // clean up added - foreach ($historyDatasets[$rev]['added'] as $field => $true) { - if (isset($prev['added'][$field])) { - unset($prev['added'][$field]); + // clean up added + foreach ($historyDatasets[$rev]['added'] as $field => $true) { + if (isset($prev['added'][$field])) { + unset($prev['added'][$field]); + } } - } - // handle removed - foreach ($prev['removed_current'] as $field => $value) { - if (!isset($historyDatasets[$rev]['removed_current'][$field])) { - $historyDatasets[$rev]['removed'][$field] = $value; + // handle removed + foreach ($prev['removed_current'] as $field => $value) { + if (!isset($historyDatasets[$rev]['removed_current'][$field])) { + $historyDatasets[$rev]['removed'][$field] = $value; + } } } - } - rex::setProperty('YFORM_HISTORY_REVISION', $rev + 1); - // dump($historyDatasets); - return $rev; - }, -); + rex::setProperty('YFORM_HISTORY_REVISION', $rev + 1); + // dump($historyDatasets); + return $rev; + }, + ); -// changes compared to current dataset -if (null !== $dataset) { + // changes compared to current dataset $changesCurrent = 'changes_to_current'; $list->addColumn($changesCurrent, '', 3, [ '', @@ -319,8 +330,8 @@ static function ($a) use (&$dataset, $table, &$historyDatasets, $actionsCell, $n // handle actions column if (0 === $changes) { $a['list']->setColumnLayout($changesCurrent, ['', '']); - $a['list']->setColumnLayout('view', ['', '']); - $a['list']->setColumnLayout('restore', ['', '']); + $a['list']->setColumnLayout('view', ['', '']); + $a['list']->setColumnLayout('restore', ['', '']); } else { $a['list']->setColumnLayout($changesCurrent, ['', $normalCell]); $a['list']->setColumnLayout('view', ['', $actionsCell]); @@ -335,48 +346,48 @@ static function ($a) use (&$dataset, $table, &$historyDatasets, $actionsCell, $n ); }, ); -} -// changes compared to previous dataset -$changesPrev = 'changes_to_prev'; -$list->addColumn($changesPrev, '', 4, [ - '', - '', -]); + // changes compared to previous dataset + $changesPrev = 'changes_to_prev'; + $list->addColumn($changesPrev, '', 4, [ + '', + '', + ]); -$sql = rex_sql::factory(); + $sql = rex_sql::factory(); -$list->setColumnFormat( - $changesPrev, - 'custom', - static function ($a) use (&$historyDatasets) { - $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0) - 1; + $list->setColumnFormat( + $changesPrev, + 'custom', + static function ($a) use (&$historyDatasets) { + $rev = rex::getProperty('YFORM_HISTORY_REVISION', 0) - 1; - $changes = 0; - $added = (isset($historyDatasets[$rev - 1]) ? count($historyDatasets[$rev - 1]['added']) : 0); - $removed = count($historyDatasets[$rev]['removed']); + $changes = 0; + $added = (isset($historyDatasets[$rev - 1]) ? count($historyDatasets[$rev - 1]['added']) : 0); + $removed = count($historyDatasets[$rev]['removed']); - $historyDataset = &$historyDatasets[$rev]['values']; + $historyDataset = &$historyDatasets[$rev]['values']; - if (isset($historyDatasets[$rev - 1])) { - $prevHistoryDataset = $historyDatasets[$rev - 1]['values']; + if (isset($historyDatasets[$rev - 1])) { + $prevHistoryDataset = $historyDatasets[$rev - 1]['values']; - foreach ($historyDataset as $field => $value) { - if ('' . $historyDataset[$field] !== '' . $prevHistoryDataset[$field]) { - ++$changes; - // dump($rev.": ".$historyDataset[$field]." - ".$prevHistoryDataset[$field]." - ".$changes); + foreach ($historyDataset as $field => $value) { + if ('' . $historyDataset[$field] !== '' . $prevHistoryDataset[$field]) { + ++$changes; + // dump($rev.": ".$historyDataset[$field]." - ".$prevHistoryDataset[$field]." - ".$changes); + } } } - } - return $changes . - ($added > 0 || $removed > 0 ? - ' (' . ($added > 0 ? '+' . $added . ' ' . rex_i18n::msg('yform_history_diff_added') : '') . - ($removed > 0 ? ($added > 0 ? ', ' : '') . '+' . $removed . ' ' . rex_i18n::msg('yform_history_diff_removed') : '') - . ')' : '' - ); - }, -); + return $changes . + ($added > 0 || $removed > 0 ? + ' (' . ($added > 0 ? '+' . $added . ' ' . rex_i18n::msg('yform_history_diff_added') : '') . + ($removed > 0 ? ($added > 0 ? ', ' : '') . '+' . $removed . ' ' . rex_i18n::msg('yform_history_diff_removed') : '') + . ')' : '' + ); + }, + ); +} $content = $list->get(); @@ -412,24 +423,27 @@ static function ($a) use (&$historyDatasets) { $historySearchForm->setObjectparams('csrf_protection', false); $historySearchForm->setHiddenField('_csrf_token', rex_csrf_token::factory($_csrf_key)->getValue()); -if (null !== $datasetId && $datasetId > 0) { +if (!$isDatasetHistory) { $historySearchForm->setValueField('text', [ 'name' => 'historySearchId', - 'label' => 'id', + 'label' => rex_i18n::msg('yform_id'), ]); +} else { + $historySearchForm->setHiddenField('dataset_id', $datasetId); } $historySearchForm->setValueField('date', [ 'name' => 'historySearchDate', - 'label' => 'Date', + 'label' => rex_i18n::msg('yform_history_timestamp'), 'widget' => 'input:text', 'current_date' => true, 'notice' => rex_i18n::msg('yform_manager_history_date_notice'), 'attributes' => '{"data-yform-tools-datepicker":"YYYY-MM-DD"}', ]); + $historySearchForm->setValueField('choice', [ 'name' => 'historySearchAction', - 'label' => 'Action', + 'label' => rex_i18n::msg('yform_history_action'), 'choices' => [ '' => rex_i18n::msg('yform_manager_actions_all'), rex_yform_manager_dataset::ACTION_CREATE => rex_i18n::msg('yform_history_action_' . rex_yform_manager_dataset::ACTION_CREATE), @@ -440,17 +454,13 @@ static function ($a) use (&$historyDatasets) { $historySearchForm->setValueField('choice', [ 'name' => 'historySearchUser', - 'label' => 'User', + 'label' => rex_i18n::msg('yform_history_user'), 'choices' => array_merge( ['' => rex_i18n::msg('yform_manager_users_all')], $users, ), ]); -if (null !== $dataset) { - $noDatasetWarning = \rex_view::warning(rex_i18n::msg('yform_history_dataset_missing')); -} - $fragment = new rex_fragment(); $fragment->setVar('class', 'edit', false); $fragment->setVar('title', rex_i18n::msg('yform_manager_search')); @@ -458,12 +468,18 @@ static function ($a) use (&$historyDatasets) { $searchForm = $fragment->parse('core/page/section.php'); $fragment = new rex_fragment(); -$fragment->setVar('title', rex_i18n::msg('yform_history_title') . ' ' . rex_i18n::msg('yform_history_dataset_id') . ': ' . $datasetId . '', false); + +if ($isDatasetHistory) { + $fragment->setVar('title', rex_i18n::msg('yform_history_title') . ' ' . rex_i18n::msg('yform_history_dataset_id') . ': ' . $datasetId . '', false); +} else { + $fragment->setVar('title', rex_i18n::msg('yform_history')); +} + $fragment->setVar('options', $options, false); $fragment->setVar('content', $content, false); $searchList = $fragment->parse('core/page/section.php'); -if (null === $dataset) { +if ((null === $dataset || !$dataset->exists()) && $datasetId > 0) { echo rex_view::warning(rex_i18n::msg('yform_history_dataset_missing')); } From 6737610c5af972d405c8bd85751616d9e94481a6 Mon Sep 17 00:00:00 2001 From: Peter Schulze Date: Tue, 11 Jun 2024 17:07:50 +0200 Subject: [PATCH 10/11] satisfying cs fixer --- plugins/manager/pages/data_history.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/manager/pages/data_history.php b/plugins/manager/pages/data_history.php index 0eff6e4bb..b0da26d83 100644 --- a/plugins/manager/pages/data_history.php +++ b/plugins/manager/pages/data_history.php @@ -330,7 +330,7 @@ static function ($a) use (&$dataset, $table, &$historyDatasets, $actionsCell, $n // handle actions column if (0 === $changes) { $a['list']->setColumnLayout($changesCurrent, ['', '']); - $a['list']->setColumnLayout('view', ['', '']); + $a['list']->setColumnLayout('view', ['', '']); $a['list']->setColumnLayout('restore', ['', '']); } else { $a['list']->setColumnLayout($changesCurrent, ['', $normalCell]); From 01570eaf02b8b3bfc8b51f05c909f6e7e171b6c5 Mon Sep 17 00:00:00 2001 From: Jan Kristinus Date: Thu, 20 Jun 2024 12:33:21 +0200 Subject: [PATCH 11/11] Sortierung der Historyliste - neueste zuerst --- plugins/manager/pages/data_history.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/manager/pages/data_history.php b/plugins/manager/pages/data_history.php index b0da26d83..03e04a7c0 100644 --- a/plugins/manager/pages/data_history.php +++ b/plugins/manager/pages/data_history.php @@ -123,7 +123,7 @@ `table_name` = ' . $sql->escape($table->getTableName()); $list = rex_list::factory($listQuery, defaultSort: [ - 'timestamp' => 'asc', + 'timestamp' => 'desc', 'hid' => 'asc', ]); $list->addFormAttribute('class', 'history-list');
' . rex_i18n::msg('yform_tablefield') . '' . rex_i18n::msg('yform_tablefield') . ' ' . rex_i18n::msg('yform_history_dataset_current') . ''. date('d.m.Y H:i:s', strtotime($timestamp)) .'' . date('d.m.Y H:i:s', strtotime($timestamp)) . '
'.rex_i18n::msg('yform_history_revision').'###VALUE###' . rex_i18n::msg('yform_history_revision') . '###VALUE###'.rex_i18n::msg('yform_history_diff_to_current').'###VALUE###' . rex_i18n::msg('yform_history_diff_to_current') . '###VALUE######VALUE###'.rex_i18n::msg('yform_history_diff_to_previous').'###VALUE###' . rex_i18n::msg('yform_history_diff_to_previous') . '###VALUE######VALUE######VALUE###' . rex_i18n::msg('yform_history_diff_to_current') . '###VALUE###' . rex_i18n::msg('yform_history_diff_to_current') . '###VALUE######VALUE######VALUE### ###VALUE######VALUE###' . rex_i18n::msg('yform_history_revision') . '###VALUE###' . rex_i18n::msg('yform_history_revision') . '###VALUE###' . rex_i18n::msg('yform_history_diff_to_current') . '###VALUE###'.rex_i18n::msg('yform_history_is_current_dataset').'' . rex_i18n::msg('yform_history_diff_to_previous') . '###VALUE###' . rex_i18n::msg('yform_history_diff_to_previous') . '###VALUE######VALUE###'.rex_i18n::msg('yform_history_is_current_dataset').'' . rex_i18n::msg('yform_history_is_current_dataset') . '