Commit 9f077d91 authored by Carsten  Rose's avatar Carsten Rose
Browse files

Merge branch 'develop' into s9535-verticalText

parents 3f18e570 20626e7b
Pipeline #3100 passed with stages
in 1 minute and 52 seconds
......@@ -53,6 +53,7 @@ composer.lock
/extension/Resources/Public/Css
/extension/Resources/Public/fonts
/extension/Resources/Public/JavaScript
/extension/Tests/selenium/tmp
/fonts
/js
/node_modules
......@@ -63,3 +64,7 @@ composer.lock
/javascript/src/.vscode
/javascript/src/npm-debug.log
/docker/chromedriver
/docker/geckodriver
/docker/run_qfq_docker.output
......@@ -9,7 +9,7 @@ variables:
stages:
- before
- build
- selenium
# - selenium
documentation:
stage: before
......@@ -48,24 +48,29 @@ release:
- scp qfq_${VERSION}_*.zip w16:qfq/releases/
- mv qfq_${VERSION}_*.zip build/qfq.zip
selenium:
stage: selenium
script:
- unzip -q build/qfq.zip -d qfq
- cd docker/
- ./run_qfq_docker.sh -no-deploy
- ./deploy_to_container.sh ../qfq
- ./run_selenium_tests_docker.sh
- echo "hello"
after_script:
# remove containers and move logs to persistent location
- cd docker; ./remove-containers.sh <<< "y"
- cd ..
- umask 002
- mkdir "$SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA"
- cp extension/Tests/selenium/selenium_logs/* "$SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA/"
- echo "Selenium Logs copied to $SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA/"
# selenium:
# stage: selenium
# script:
# - unzip -q build/qfq.zip -d qfq
# - cd docker/
# - ./run_qfq_docker.sh -no-deploy
# - ./deploy_to_container.sh ../qfq
# - ./run_selenium_tests_docker.sh
# - echo "hello"
# after_script:
# # remove containers and move logs to persistent location
# - cd docker; ./remove-containers.sh <<< "y"
# - cd ..
# - umask 002
# - mkdir "$SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA"
# - cp extension/Tests/selenium/selenium_logs/* "$SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA/"
# - echo "Selenium Logs copied to $SELENIUM_LOGS_PATH/$CI_COMMIT_SHORT_SHA/"
# - echo "Or download result (log/screenshot) in gitlab under CI/CD > Pipelines <job> > right side 'Artifacts'"
# artifacts:
# expire_in: 1 week
# paths:
# - extension/Tests/selenium/selenium_logs/
.. ==================================================
.. Header hierachy
.. Header hierarchy
.. ==
.. --
.. ^^
......@@ -36,6 +36,56 @@ Features
Bug Fixes
^^^^^^^^^
Version 19.12.0
---------------
Date: <date>
Notes
^^^^^
* Switch the whole homepage to readonly: FormModeGlobal and STORE_USER
Features
^^^^^^^^
* TinyMCE: grey out controls when readonly.
* Mockup:
* Update files to get CSS & JS files from their own directory structure (not an installed QFQ extension).
* Add fontawesome, tablesorter to mockup 'formCheckbox.html'.
* CI: Download selenium logs (only failed) under artifacts.
* Dev: .gitignore: exclude some docker & selenium.
* Merge Selenium Python Checks into Master.
* #9686 / html decode and sanitize an export filename to become the 'save as'-filename.
* #9666 / min-width for extraButtonInfo.
* FormEditor: optimize minWidth for 'rowLabelInputNote' field.
Bug Fixes
^^^^^^^^^
* #9720 / Checkbox dynamic update varoious settings:
* Multi Plain Vertical & Horizontal, Checkbox Multi BS.
* Fixed that label of 'checkbox' are bold and label of 'checkbox-inline' are normal.
* #7974 / TinyMCE: ReadOnly.
* #9424 / modeSql: skip if it starts with '#'.
* #9531 / File Upload Required.
* #9674 / Select Required Dynamic Update.
* #9678 / textarea now trigger DynamicUpdate.
* #9679 / FormModeGlobal: add STORE_USER - system wide readonly.
* #9690 / Select Required.
* #9691 / Checkbox: dynamic update > readonly. HTML ID for checkbox elements. Dynamic update switch 'readonly' for 'checkbox plain multi' and 'radio plain multi'.
* #9692 / Keyboard Select Checkbox.
* #9720 / Checkbox: Various setups with dynamic update.
* #9733 / Identiy different tabs. Record lock for same tab will always be granted.
* #9734 / Fix 'dirty lock release' - leaving a dirty form without closing, leaves a stale lock record. Added a releaselock() before window.unload. Dirty remove on goBack.
* #9735 / File Delete: no dirty trigger.
* Download / PDF merge: skip leading errors, interpret only 'Could not merge encrypted files'.
* DragAndDrop broken: after refactoring Support.php, the dragAndDrop was broken - missed init of '$store'.
Version 19.11.3
---------------
......@@ -49,14 +99,17 @@ Features
* #8886 / Check pattern: after focus lost.
* #9655 / Checkboxes and radios now defined with a min-width in horizontal plain mode.
* #9617:
* #9617 / formModeGlobal:
* Two modes now implemented 'requiredOff' and 'requiredOffButMark'.
* formModeGlobal: renamed skipRequiredCheck to requiredOffButMark .
* Keep required marks after save.
* Stop hiding helpblocks per default, set with class qfq-only-active-error.
* Two modes of 'formModeGlobal' available: 'requiredOff' and 'requiredOffButMark'.
* 'requiredOffButMark':
* Radio: new class 'qfq-disabled' if readonly is set. softer blue. mark disabled - changed hover. text in darker orange. simple-error renamed to qfq-notify - removed box around error.
* Renamed temporary 'skipRequiredCheck' to 'requiredOffButMark'.
* Keep required marks after save.
* Stop hiding helpblocks per default, set with class qfq-only-active-error.
* Radio: new class 'qfq-disabled' if readonly is set. Softer blue. Mark disabled - changed hover. Text in darker orange.
Simple-error renamed to qfq-notify - removed box around error.
* New default class for 'form' tag: 'qfq-notify'.
* Manual.rst: Add info for 'letter-no-break'.
* Add validator.js to list of used packages.
......@@ -86,21 +139,17 @@ Date: 25.11.2019
Notes
^^^^^
* Fantastic new formModeGlobal=skipRequiredCheck: fill's '{{allRequiredGiven:V}}' before save to 1 (all given) else 0.
* Enhance formModeGlobal=requiredOff/-ButMark (temporarily skipRequiredCheck): fill's '{{allRequiredGiven:V}}' before
save to 1 (all given) else 0.
Offers user to save form, even if not all required data are given and offers application logic to check easily if all
required fields has been fillled.
* formModeGlobal=requiredOff is now deprecated but will still work.
required fields has been filled.
Features
^^^^^^^^
* #9526 / Mark required fields more visible
* #9526 / Mark required fields more visible.
* #9617 / Improve 'formModeGlobal=requiredOff'.
* New mode name 'skipRequiredCheck'.
* 'requiredOff' is replaced by 'skipRequiredCheck' and now deprecated.
* Add documentation for 'skipRequiredCheck:S' & 'allRequiredGiven:V'
* Feature `Form.formModeGlobal` implemented - STORE_SIP overwrites form definition.
* New STORE_VAR variable 'allRequiredGiven'. Becomes '1' if all required fields are given, else 0.
......@@ -114,11 +163,11 @@ Bug Fixes
* #7639 / subrecord drag n drop:
* `orderInterval` has not been respected.
* Update Manual.rst
* Update Manual.rst.
* Fake STORE_SIP so it can be used during processing sql1.
* The record, currently loaded into form, is available via STORE_RECORD.
* Check for id/_id and ord/_ord
* Throw meaningful exception if missing 'id' or 'ord'
* Check for id/_id and ord/_ord.
* Throw meaningful exception if missing 'id' or 'ord'.
* Fixes bug that no mime_type_content is called if there is on file.
* Fix broken regex101 url.
......
......@@ -54,12 +54,12 @@ Neue Versionsnummer
* Update the version number in this document (topic 6)
* Commit & Push new version changes to master branch:
New version 19.11.3
New version 19.12.0
6) **New Tag**:
git tag v19.11.3
git push -u origin v19.11.3
git tag v19.12.0
git push -u origin v19.12.0
7) Tickets:
* Schliessen und der QFQ Version zuweisen.
......
......@@ -484,6 +484,9 @@ Server Response
### Record lock
Request, extend or release a lock for a record, identified by the SIP. The SIP contain a SIP_FORM and a SIP_R (record id).
See `Documentation-develop/diagram` for a state diagram.
To detect record change at time of 'record lock' or 'record save', a MD5 hash is provided from the server
and needs to pass back to dirty.php as well.
......@@ -497,6 +500,7 @@ URL Parameters
: `s=<SIP>` (form, r)
: `action=lock`, `action=extend`, `action=release>`
: `recordHashMd5=<value of hidden form element 'recordHashMd5'>`
: `tabUniqId=<unique id>`
Server Response
: The response contains an [Lock Response].
......@@ -509,7 +513,7 @@ JSON Response from the server (extended [Minimal Response]) containing:
: {
: "status": "success"|"error"|"conflict"|"conflict_allow_force",
: "message": "<message>"e5
: }
: }
`status` indicates how the request has been fulfilled by the server.
On`"success"`, the Client display nothing to the user.
......@@ -518,6 +522,20 @@ On `"conflict"` the Client opens the alert as modal dialog (user can't change an
form' button.
On `"conflict_allow_force"` the Client opens the alert non-modal (default).
### tabUniqId
* Client: Every browser tab get's a `tabUniqId` (timestamp) as soon as the first time a lock is requested (acquire).
This `tabUniqId` remains, until the tab is close. It is saved in window.name.
* Server: On lock request, the `tabUniqId` is saved in dirty record.
* The `tabUniqId` helps to implement 'optimistic locking': if there is no argument against 'grant lock' - grant it.
Example: In browser tab 'A' a lock is requested. For unknown reason, there is a stale lock for the
user session and the given tab id: grant the log.
* Unexpected async behaviour in client: On page reload (F5), the 'lock release' might come after 'lock acquire'.
The form goes in 'read only' mode - an additional page reload (F5) solves the situation - but this is boring.
### Drag And Drop (sort)
......
<!-- -*- markdown -*- -->
# Record locking
## Concept: Late locking
* A lock is required on first modification.
* Multiple forms might open the same record, all seems to have write access. The first one who modifies the record
get the lock, all following will switch to form=readonly on their first try to modify the record.
## Lock mode: Exclusive
* A lock can't be overwritten.
## Lock mode: Advisory
* A lock can be ignored.
* Last save win's.
## Lock mode: None
* No locking at all.
# Workarounds
* At least one Browser (FF 71, maybe other in the future too), do not allow to wrap the 'leave page' dialog anymore.
This might result in stale lock files (modified record, click on browser tab close or any link), cause the lock
logic does not know that the user leaves the page.
* Workaround: before 'do you want to leave the page' appears, the lock is released, independent if the user answers 'no'.
As soon as the users modifies the record again, a new lock is acquired. This is better than a stale record lock.
* Reload a page (F5) on a modified record, opens the form in readonly mode (record lock found).
* Reason: the lock release is fired by the browser AFTER form load - than the lock-logic reports 'record is already locked'.
* Workaround: with the above workaround, this does not happen anymore. Nevertheless, a 'tabUniqId' has been implemented.
That one is saved as record lock and a page reload origin can be identified as the same tab as where the lock has been
acquired.
= State Diagram =
See `Documentation-develop/diagram` for a state diagram.
**To run/update SELENIUM test, please check docker/README.md.**
Create new Tests
================
* Set up new forms and reports.
* Dump new database.
* Copy dump to become now initial database
* Update SELENIUM Python tests
......@@ -7,7 +7,7 @@
.. ;;
.. ,,
..
.. --------------------------------------------------
.. --------------------------------------------used to the update the records specified ------
.. Best Practice T3 reST: https://docs.typo3.org/m/typo3/docs-how-to-document/master/en-us/WritingReST/CheatSheet.html
.. Reference: https://docs.typo3.org/m/typo3/docs-how-to-document/master/en-us/WritingReST/Index.html
.. Italic *italic*
......@@ -2255,7 +2255,7 @@ If a timeout expires, the lock becomes invalid. During the next change in a form
A lock is assigned to a record of a table. Multiple forms, with the same primary table, uses the same lock for a given record.
If a `Form` acts on further records (e.g. via FE action), those records are not protected by this basic record locking.
If a `Form` acts on further records (e.g. via FE action), those further records are not protected by this basic record locking.
If a user tries to delete a record and another user already owns a lock on that record, the delete action is denied.
......@@ -2544,7 +2544,7 @@ Parameter
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLdap | | Enable LDAP as 'Typeahead' data source. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLdapSearch | string | Regular LDAP search expression. E.g.: `(|(cn=*?*)(mail=*?*))` |
| typeAheadLdapSearch | string | Regular LDAP search expression. E.g.: `(|(cn=*?*)(mail=*?*))`   |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLdapValuePrintf | string | Value formatting of LDAP result, per entry. E.g.: `'%s / %s / %s', mail, roomnumber, telephonenumber` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
......@@ -2559,6 +2559,9 @@ Parameter
| mode | string | The value `readonly` will activate a global readonly mode of the form - the user can't change any data. |
| | | See :ref:`form-mode-global` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| activeFirstRequiredTab | digit | 0: off, 1: (default) - with formModeGlobal=requiredOffButMark bring pill to front on save. |
| | | See :ref:`form-mode-global` |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| enterAsSubmit | digit | 0: off, 1: Pressing *enter* in a form means *save* and *close*. Takes default from configuration_. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| submitButtonText | string | Show a save button at the bottom of the form, with <submitButtonText> . See `submitButtonText`_. |
......@@ -2614,9 +2617,6 @@ Parameter
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| requiredPosition | int | See requiredPosition_ . |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| minWidth | int | See checkboxRadioMinWidth_ . |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
* Example:
......@@ -2732,6 +2732,11 @@ Mode
* On lost focus.
* When the user saves the record.
* After saving the record, by default the first pill with a missing input comes to front. This behaviour can be
switch on/off with `form.parameter.requiredOffButMark=0|1`
Extra
;;;;;
......@@ -7618,7 +7623,7 @@ A dedicated `Form`, without any `FormElements`, is used to define the reorder lo
Fields:
* Name: <custom form name> - used in Part 1 in the `_data-dnd-api` variable.
* Table: <table with the element records> - used to the update the records specified by `dragAndDropOrderSql`.
* Table: <table with the element records> - used to update the records specified by `dragAndDropOrderSql`.
* Parameter:
......@@ -7663,6 +7668,7 @@ QFQ CSS Classes
* `qfq-100` - assigned to different tags, makes an element 'width: 100%'.
* `qfq-left`- assigned to different tags, Text align left.
* `qfq-sticky` - assigned to `<thead>`, makes the header sticky.
* `qfq-badge`, `qfq-badge-error`, `qfq-badge-warning`, `qfq-badge-success`, `qfq-badge-info`, `qfq-badge-invers` - colorized BS3 badges.
* `letter-no-break` - assigned to a `div` will protect a paragraph (CSS: page-break-before: avoid;) not to break around
a page border (converted to PDF via wkhtml). Take care that `qfq-letter.css` is included in TypoScript setup.
......
......@@ -36,6 +36,57 @@ Features
Bug Fixes
^^^^^^^^^
Version 19.12.0
---------------
Date: 17.12.2019
Notes
^^^^^
* Switch the whole homepage to readonly: FormModeGlobal and STORE_USER
Features
^^^^^^^^
* TinyMCE: grey out controls when readonly.
* Mockup:
* Update files to get CSS & JS files from their own directory structure (not an installed QFQ extension).
* Add fontawesome, tablesorter to mockup 'formCheckbox.html'.
* CI: Download selenium logs (only failed) under artifacts.
* Dev: .gitignore: exclude some docker & selenium.
* Merge Selenium Python Checks into Master.
* #9686 / html decode and sanitize an export filename to become the 'save as'-filename.
* #9666 / min-width for extraButtonInfo.
* FormEditor: optimize minWidth for 'rowLabelInputNote' field.
Bug Fixes
^^^^^^^^^
* #9720 / Checkbox dynamic update varoious settings:
* Multi Plain Vertical & Horizontal, Checkbox Multi BS.
* Fixed that label of 'checkbox' are bold and label of 'checkbox-inline' are normal.
* #7974 / TinyMCE: ReadOnly.
* #9424 / modeSql: skip if it starts with '#'.
* #9531 / File Upload Required.
* #9674 / Select Required Dynamic Update.
* #9678 / textarea now trigger DynamicUpdate.
* #9679 / FormModeGlobal: add STORE_USER - system wide readonly.
* #9690 / Select Required.
* #9691 / Checkbox: dynamic update > readonly. HTML ID for checkbox elements. Dynamic update switch 'readonly' for 'checkbox plain multi' and 'radio plain multi'.
* #9692 / Keyboard Select Checkbox.
* #9720 / Checkbox: Various setups with dynamic update.
* #9733 / Identiy different tabs. Record lock for same tab will always be granted.
* #9734 / Fix 'dirty lock release' - leaving a dirty form without closing, leaves a stale lock record. Added a releaselock() before window.unload. Dirty remove on goBack.
* #9735 / File Delete: no dirty trigger.
* Download / PDF merge: skip leading errors, interpret only 'Could not merge encrypted files'.
* DragAndDrop broken: after refactoring Support.php, the dragAndDrop was broken - missed init of '$store'.
Version 19.11.3
---------------
......
......@@ -21,8 +21,8 @@
; you can use in 'conf.py'
project = QFQ - Quick Form Query
version = 19.11
release = 19.11.3
version = 19.12
release = 19.12.0
t3author = Carsten Rose
copyright = since 2017 by the author
......
......@@ -440,6 +440,16 @@ module.exports = function (grunt) {
expand: true,
flatten: true
},
{
cwd: 'node_modules/font-awesome/css/',
src: [
'font-awesome.min.css'
],
dest: 'css/',
filter: 'isFile',
expand: true,
flatten: true
},
{
cwd: 'node_modules/font-awesome/fonts/',
expand: true,
......@@ -448,6 +458,15 @@ module.exports = function (grunt) {
],
dest: typo3_fonts,
flatten: true
},
{
cwd: 'node_modules/font-awesome/fonts/',
expand: true,
src: [
'*'
],
dest: 'fonts/',
flatten: true
}
]
},
......
This diff is collapsed.
This diff is collapsed.
......@@ -31,6 +31,7 @@ class QfqController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
*/
public function showAction() {
$html = '';
$origErrorReporting = '';
$flagOk = false;
......
......@@ -772,6 +772,11 @@ EOF;
if ($wrapName == FE_WRAP_LABEL) {
$wrapArray[0] = Support::insertAttribute($wrapArray[0], 'style', 'text-align: ' . $formElement[F_FE_LABEL_ALIGN] . ';'); // might be problematic, if there is already a 'class' defined.
}
// Insert 'required="required"' for checkboxes and radios
if ($wrapName == FE_WRAP_INPUT && $formElement[FE_MODE] == FE_MODE_REQUIRED &&
($formElement[FE_TYPE] == FE_TYPE_CHECKBOX || $formElement[FE_TYPE] == FE_TYPE_RADIO)) {
$wrapArray[0] = Support::insertAttribute($wrapArray[0], 'required', 'required'); // might be problematic, if there is already a 'class' defined.
}
}
return $wrapArray[0] . $htmlElement . $wrapArray[1];
......@@ -807,7 +812,7 @@ EOF;
// Label
if ($formElement[FE_BS_LABEL_COLUMNS] != '0') {
$htmlLabel = $this->buildLabel($htmlFormElementName, $formElement[FE_LABEL], $addClassRequired[FE_LABEL] ?? '');
$htmlLabel = HelperFormElement::buildLabel($htmlFormElementName, $formElement[FE_LABEL], $addClassRequired[FE_LABEL] ?? '');
}
$html .= $this->customWrap($formElement, $htmlLabel, FE_WRAP_LABEL, $formElement[FE_BS_LABEL_COLUMNS],
......
......@@ -1046,6 +1046,7 @@ const F_NEW_BUTTON_CLASS = SYSTEM_NEW_BUTTON_CLASS;
const F_NEW_BUTTON_GLYPH_ICON = SYSTEM_NEW_BUTTON_GLYPH_ICON;
const F_ENTER_AS_SUBMIT = SYSTEM_ENTER_AS_SUBMIT;
const F_ACTIVATE_FIRST_REQUIRED_TAB = 'activeFirstRequiredTab';
const F_DRAG_AND_DROP_ORDER_SQL = 'dragAndDropOrderSql';
const F_ORDER_INTERVAL = 'orderInterval';
......@@ -1252,6 +1253,7 @@ const FE_INPUT_AUTOCOMPLETE = 'autocomplete';
const FE_TMP_EXTRA_BUTTON_HTML = '_extraButtonHtml'; // will be filled on the fly during building extrabutton
const FE_CHECKBOX_CHECKED = 'checked';
const FE_CHECKBOX_UNCHECKED = 'unchecked';
const FE_ITEM_LIST = 'itemList';
const FE_RECORD_DESTINATION_TABLE = 'recordDestinationTable';
const FE_RECORD_SOURCE_TABLE = 'recordSourceTable';
const FE_TRANSLATE_ID_COLUMN = 'translateIdColumn';
......@@ -1328,6 +1330,8 @@ const FE_ORDER_INTERVAL_DEFAULT = '10';
const FE_ORDER_COLUMN = 'orderColumn';
const FE_DND_TABLE = 'dndTable';
const FE_TMP_CLASS_OPTION = '_classOption';
const MODE_ENCODE = 'encode';
const MODE_DECODE = 'decode';
const MODE_NONE = 'none';
......@@ -1812,6 +1816,7 @@ const DIRTY_API_ACTION_EXTEND = 'extend';
const LOCK_NOT_FOUND = 0;
const LOCK_FOUND_OWNER = 1;
const LOCK_FOUND_CONFLICT = 2;
const TAB_UNIQ_ID = 'tabUniqId'; // Uniq identifier per tab: no values stored behind the identifier - might change.
// AutoCron
const AUTOCRON_MAX_AGE_MINUTES = 10;
......@@ -1949,3 +1954,20 @@ const SETTING_TABLESORTER_MODE = 'mode';
const SETTING_TABLESORTER_MODE_DELETE = 'delete';
const SETTING_TABLESORTER_CLEAR = 'Clear';
// Object: Type
const T_LABEL = 't_label';
const T_INPUT = 't_input';
const T_NOTE = 't_note';
const T_ = 't_note';
// Object: Item
const I_TYPE = 'type';
const I_ID = 'id';
const I_VALUE = 'value';
const I_CLASS = 'class';
const I_ATTRIBUTE = 'attribute';
// Object: extra for checkboxes
const I_CHECKED = 'checked';
const I_UNCHECKED = 'unchecked';
......@@ -74,7 +74,7 @@ class Database {
$this->store = Store::getInstance();
$storeSystem = $this->store->getStore(STORE_SYSTEM);
$this->sqlLog = $storeSystem[SYSTEM_SQL_LOG];
$this->sqlLog = $storeSystem[SYSTEM_SITE_PATH] . '/' . $storeSystem[SYSTEM_SQL_LOG];
$dbInit = $storeSystem[SYSTEM_DB_INIT];
$config = $this->getConnectionDetails($dbIndex, $storeSystem);
......
......@@ -185,6 +185,10 @@ $UPDATE_ARRAY = array(
"ALTER TABLE `Setting` CHANGE `created` `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP; ",
],
'19.12.0' => [
"ALTER TABLE `Dirty` ADD `tabUniqId` VARCHAR(32) NOT NULL AFTER `recordHashMd5`;",
],
);
......
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment