From a3df7a724ca8a4dd73b9f5e94f6e29436b8aa92c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 10 Aug 2018 20:19:16 +0200 Subject: [PATCH] CSV import, also from file, and more UX improvements --- Makefile | 4 + _json_typehints.php | 1 + app/Http/Controllers/TableEditController.php | 59 +++++++-- app/Tables/Changeset.php | 28 +++-- app/View/WidgetFactory.php | 18 +++ porklib/Utils/Utils.php | 21 +++- public/fonts/fa-dtbl-1-preview.html | 108 +++++++++++------ public/fonts/fa-dtbl-1.css | 40 +++--- public/fonts/fa-dtbl-1.eot | Bin 11740 -> 12108 bytes public/fonts/fa-dtbl-1.svg | 51 ++++---- public/fonts/fa-dtbl-1.ttf | Bin 11560 -> 11928 bytes public/fonts/fa-dtbl-1.woff2 | Bin 5760 -> 5964 bytes resources/assets/fa-config/wanted.ini | 1 + .../assets/js/components/ColumnEditor.vue | 26 ++-- resources/assets/js/components/RowsEditor.vue | 114 +++++++++++++----- resources/assets/js/components/_base.scss | 5 + .../table/propose/add-rows-csv.blade.php | 49 ++++++-- .../views/table/propose/add-rows.blade.php | 1 + 18 files changed, 371 insertions(+), 155 deletions(-) diff --git a/Makefile b/Makefile index 72f3b85..e339e40 100644 --- a/Makefile +++ b/Makefile @@ -10,3 +10,7 @@ ana: npm run dev-analyze prod: npm run prod +bc: + php artisan view:clear + php artisan cache:clear + php artisan ide-helper:generate diff --git a/_json_typehints.php b/_json_typehints.php index 6565ac6..6c1ad90 100644 --- a/_json_typehints.php +++ b/_json_typehints.php @@ -13,6 +13,7 @@ interface RowData {} * @property bool $_new - row is new in the changeset * @property bool $_remove - marked to be removed * @property mixed[] $_orig - original values before transformation, key by CID + * @property mixed[] $_loadvals - values after transformation, key by CID / for use by JS to detect changes since page load * @property string[] $_changed - values that were changed */ interface DecoratedRow extends RowData {} diff --git a/app/Http/Controllers/TableEditController.php b/app/Http/Controllers/TableEditController.php index a37ca85..7829546 100644 --- a/app/Http/Controllers/TableEditController.php +++ b/app/Http/Controllers/TableEditController.php @@ -60,8 +60,9 @@ class TableEditController extends Controller if ($tableModel === null) abort(404, "No such table."); if ($tab == null) $tab = 'edit-rows'; - $tabs = ['edit-rows', 'add-rows', 'manage-columns', 'review']; - if (!in_array($tab, $tabs)) abort(404, "No such tab: $tab"); + + $method = camel_case($tab); + if (!method_exists($this, $method)) abort(404, "No such tab: $tab"); $changeset = $this->getChangeset($tableModel); @@ -69,7 +70,7 @@ class TableEditController extends Controller dd($changeset); } - return $this->{camel_case($tab)}($changeset); + return $this->$method($changeset); } /** @noinspection PhpUnusedPrivateMethodInspection */ @@ -101,6 +102,18 @@ class TableEditController extends Controller ]); } + /** @noinspection PhpUnusedPrivateMethodInspection */ + private function addRowsCsv(Changeset $changeset) + { + $columns = $changeset->fetchAndTransformColumns(); + + return view('table.propose.add-rows-csv', [ + 'changeset' => $changeset, + 'table' => $changeset->table, + 'columns' => collect($columns), + ]); + } + /** @noinspection PhpUnusedPrivateMethodInspection */ private function manageColumns(Changeset $changeset) { @@ -143,13 +156,43 @@ class TableEditController extends Controller $resp = $updated; break; + case 'row.add-csv': + $fname = 'csv-file'; + if ($request->hasFile($fname)) { + try { + $file = $request->file($fname); + if ($file->isValid() && $file->isReadable()) { + $handle = $file->openFile(); + $csv = Utils::csvToArray($handle); + if (empty($csv)) throw new \Exception("Failed to parse CSV file."); + + $changeset->addFilledRows($csv); + $handle = null; + } else { + throw new \Exception("File not valid."); + } + } catch (\Exception $e) { + return $this->backWithErrors(['csv-file' => $e->getMessage()]); + } + } + else { + try { + $text = trim($input->data); + if (empty($text)) throw new \Exception("Empty CSV field and no file uploaded."); + $changeset->addFilledRows(Utils::csvToArray($text)); + } catch (\Exception $e) { + return $this->backWithErrors(['data' => $e->getMessage()]); + } + } + break; + case 'row.remove': $isNew = $changeset->isNewRow($input->id); $changeset->rowRemove($input->id); $resp = $isNew ? null : $changeset->fetchAndTransformRow($input->id); break; - case 'rows.remove-empty-new': + case 'row.remove-empty-new': $changeset->removeEmptyNewRows(); break; @@ -162,14 +205,6 @@ class TableEditController extends Controller $changeset->addBlankRows($input->count); break; - case 'rows.add-csv': - try { - $changeset->addFilledRows(Utils::csvToArray($input->data)); - } catch (\Exception $e) { - return $this->backWithErrors(['data' => $e->getMessage()]); - } - break; - case 'col.update': $data = (object)$input->data; $resp = $changeset->columnUpdate($data); diff --git a/app/Tables/Changeset.php b/app/Tables/Changeset.php index 391d057..3c7c948 100644 --- a/app/Tables/Changeset.php +++ b/app/Tables/Changeset.php @@ -188,16 +188,19 @@ class Changeset $row->_orig = []; } + if ($decorate) { + $row->_orig = array_diff((array)$row, []); + // remove junk + unset($row->_orig['_id']); + unset($row->_orig['_new']); + unset($row->_orig['_remove']); + unset($row->_orig['_changed']); + unset($row->_orig['_orig']); + } + if ($this->isNewRow($row->_id)) { if ($decorate) { $row->_new = true; - $row->_orig = array_diff((array)$row, []); - // remove junk - unset($row->_orig['_id']); - unset($row->_orig['_new']); - unset($row->_orig['_remove']); - unset($row->_orig['_changed']); - unset($row->_orig['_orig']); } return $row; } @@ -235,6 +238,16 @@ class Changeset unset($row->_row_pivot); + if ($decorate) { + $row->_loadvals = array_diff((array)$row, []); + // remove junk + unset($row->_loadvals['_id']); + unset($row->_loadvals['_new']); + unset($row->_loadvals['_remove']); + unset($row->_loadvals['_changed']); + unset($row->_loadvals['_orig']); + } + return $row; } @@ -582,6 +595,7 @@ class Changeset 'type' => "string", 'title' => "Column {$num}", 'id' => $cid, + '_new' => true, ]; $this->newColumns[$cid] = $col; diff --git a/app/View/WidgetFactory.php b/app/View/WidgetFactory.php index 1be780a..c74cfc0 100644 --- a/app/View/WidgetFactory.php +++ b/app/View/WidgetFactory.php @@ -38,6 +38,19 @@ class WidgetFactory ""; } + public function labeledPar($label, $text, $extraClasses='', $escape=true) + { + if (false === strpos($extraClasses, 'mb-')) $extraClasses .= ' mb-2'; + + return + "
". + "". + "

fieldCols".e($extraClasses)."\">". + ($escape ? e($text) : $text) . + "

". + "
"; + } + /** * Convert the given string to a-href if it is a link. * @@ -85,6 +98,11 @@ class WidgetFactory return $this->baseWidget('input', $name, $label)->type('email'); } + public function file($name, $label) + { + return $this->baseWidget('input', $name, $label)->type('file'); + } + public function checkbox($name, $label) { return (new CheckboxWidget('checkbox', $name, $label)) diff --git a/porklib/Utils/Utils.php b/porklib/Utils/Utils.php index 7b2789f..45497e5 100644 --- a/porklib/Utils/Utils.php +++ b/porklib/Utils/Utils.php @@ -1014,8 +1014,25 @@ class Utils return $key; } - public static function csvToArray(string $data) + /** + * @param \SplFileObject|string $data + * @return array + */ + public static function csvToArray($data) { - return array_map('str_getcsv', explode("\n", $data)); + if ($data instanceof \SplFileObject) { + $data->setFlags(\SplFileObject::SKIP_EMPTY | \SplFileObject::DROP_NEW_LINE); + $lines = []; + while (! $data->eof()) { + $line = $data->fgetcsv(); + if ($line !== null) { + $lines[] = $line; + } + } + return $lines; + } + else { + return array_map('str_getcsv', explode("\n", $data)); + } } } diff --git a/public/fonts/fa-dtbl-1-preview.html b/public/fonts/fa-dtbl-1-preview.html index dc7a923..5824a59 100644 --- a/public/fonts/fa-dtbl-1-preview.html +++ b/public/fonts/fa-dtbl-1-preview.html @@ -184,6 +184,7 @@ .fa-key-modern:before, .fa-link:before, .fa-moon-o:before, +.fa-paper-plane-o:before, .fa-pencil:before, .fa-plus:before, .fa-question-circle:before, @@ -198,6 +199,7 @@ .fa-th-list:before, .fa-trash-o:before, .fa-undo:before, +.fa-upload:before, .fa-user:before, .fa-user-circle-o:before, .fa-user-plus:before, @@ -240,25 +242,27 @@ .fa-key-modern:before { content: "\f114"; } .fa-link:before { content: "\f115"; } .fa-moon-o:before { content: "\f116"; } -.fa-pencil:before { content: "\f117"; } -.fa-plus:before { content: "\f118"; } -.fa-question-circle:before { content: "\f119"; } -.fa-reply:before { content: "\f11a"; } -.fa-sign-in:before { content: "\f11b"; } -.fa-sign-out:before { content: "\f11c"; } -.fa-spinner:before { content: "\f11d"; } -.fa-star:before { content: "\f11e"; } -.fa-star-o:before { content: "\f11f"; } -.fa-sun-o:before { content: "\f120"; } -.fa-table:before { content: "\f121"; } -.fa-th-list:before { content: "\f122"; } -.fa-trash-o:before { content: "\f123"; } -.fa-undo:before { content: "\f124"; } -.fa-user:before { content: "\f125"; } -.fa-user-circle-o:before { content: "\f126"; } -.fa-user-plus:before { content: "\f127"; } -.fa-users:before { content: "\f128"; } -.fa-wrench:before { content: "\f129"; } +.fa-paper-plane-o:before { content: "\f117"; } +.fa-pencil:before { content: "\f118"; } +.fa-plus:before { content: "\f119"; } +.fa-question-circle:before { content: "\f11a"; } +.fa-reply:before { content: "\f11b"; } +.fa-sign-in:before { content: "\f11c"; } +.fa-sign-out:before { content: "\f11d"; } +.fa-spinner:before { content: "\f11e"; } +.fa-star:before { content: "\f11f"; } +.fa-star-o:before { content: "\f120"; } +.fa-sun-o:before { content: "\f121"; } +.fa-table:before { content: "\f122"; } +.fa-th-list:before { content: "\f123"; } +.fa-trash-o:before { content: "\f124"; } +.fa-undo:before { content: "\f125"; } +.fa-upload:before { content: "\f126"; } +.fa-user:before { content: "\f127"; } +.fa-user-circle-o:before { content: "\f128"; } +.fa-user-plus:before { content: "\f129"; } +.fa-users:before { content: "\f12a"; } +.fa-wrench:before { content: "\f12b"; } @@ -274,7 +278,7 @@
-

fa-dtbl-1 contains 42 glyphs:

+

fa-dtbl-1 contains 44 glyphs:

Toggle Preview Characters
@@ -581,6 +585,19 @@
+
+
+ PpPpPpPpPpPpPpPpPpPp +
+
+ 12141618212436486072 +
+
+ + +
+
+
PpPpPpPpPpPpPpPpPpPp @@ -590,7 +607,7 @@
- +
@@ -603,7 +620,7 @@
- +
@@ -616,7 +633,7 @@
- +
@@ -629,7 +646,7 @@
- +
@@ -642,7 +659,7 @@
- +
@@ -655,7 +672,7 @@
- +
@@ -668,7 +685,7 @@
- +
@@ -681,7 +698,7 @@
- +
@@ -694,7 +711,7 @@
- +
@@ -707,7 +724,7 @@
- +
@@ -720,7 +737,7 @@
- +
@@ -733,7 +750,7 @@
- +
@@ -746,7 +763,7 @@
- +
@@ -759,7 +776,20 @@
- + +
+ + +
+
+ PpPpPpPpPpPpPpPpPpPp +
+
+ 12141618212436486072 +
+
+ +
@@ -772,7 +802,7 @@
- +
@@ -785,7 +815,7 @@
- +
@@ -798,7 +828,7 @@
- +
@@ -811,7 +841,7 @@
- +
@@ -824,7 +854,7 @@
- +
diff --git a/public/fonts/fa-dtbl-1.css b/public/fonts/fa-dtbl-1.css index 85efae6..b8e2d47 100644 --- a/public/fonts/fa-dtbl-1.css +++ b/public/fonts/fa-dtbl-1.css @@ -61,22 +61,24 @@ .fa-key-modern::before { content: "\f114"; } .fa-link::before { content: "\f115"; } .fa-moon-o::before { content: "\f116"; } -.fa-pencil::before { content: "\f117"; } -.fa-plus::before { content: "\f118"; } -.fa-question-circle::before { content: "\f119"; } -.fa-reply::before { content: "\f11a"; } -.fa-sign-in::before { content: "\f11b"; } -.fa-sign-out::before { content: "\f11c"; } -.fa-spinner::before { content: "\f11d"; } -.fa-star::before { content: "\f11e"; } -.fa-star-o::before { content: "\f11f"; } -.fa-sun-o::before { content: "\f120"; } -.fa-table::before { content: "\f121"; } -.fa-th-list::before { content: "\f122"; } -.fa-trash-o::before { content: "\f123"; } -.fa-undo::before { content: "\f124"; } -.fa-user::before { content: "\f125"; } -.fa-user-circle-o::before { content: "\f126"; } -.fa-user-plus::before { content: "\f127"; } -.fa-users::before { content: "\f128"; } -.fa-wrench::before { content: "\f129"; } +.fa-paper-plane-o::before { content: "\f117"; } +.fa-pencil::before { content: "\f118"; } +.fa-plus::before { content: "\f119"; } +.fa-question-circle::before { content: "\f11a"; } +.fa-reply::before { content: "\f11b"; } +.fa-sign-in::before { content: "\f11c"; } +.fa-sign-out::before { content: "\f11d"; } +.fa-spinner::before { content: "\f11e"; } +.fa-star::before { content: "\f11f"; } +.fa-star-o::before { content: "\f120"; } +.fa-sun-o::before { content: "\f121"; } +.fa-table::before { content: "\f122"; } +.fa-th-list::before { content: "\f123"; } +.fa-trash-o::before { content: "\f124"; } +.fa-undo::before { content: "\f125"; } +.fa-upload::before { content: "\f126"; } +.fa-user::before { content: "\f127"; } +.fa-user-circle-o::before { content: "\f128"; } +.fa-user-plus::before { content: "\f129"; } +.fa-users::before { content: "\f12a"; } +.fa-wrench::before { content: "\f12b"; } diff --git a/public/fonts/fa-dtbl-1.eot b/public/fonts/fa-dtbl-1.eot index f7fcd1ff9ba62ba14cb3d7dd1e7bb3df6e92215d..d2f207c138ebfdfe53960c4505b0227719e24ef5 100644 GIT binary patch delta 850 zcmY*XT}TvB6h3Emc4l?famRI68C~7kpV`sXP1af$)LN(qi=Z$NK`^InQ)tzxEG&ZE zUZR2`nU{iIdg-Me1Yi1l*utRbhYCswgUH^Z2LpRBo$2gG55Yb6@_pa^&Nmcw%04$j&gny^~!?Ik!xe2>~0jMquWfSK% z-(VoxRY}r?UZ|}obcL95;tV7z49lfV53{Q(&H+8mZSoB>MV1G9%UovC3|BNo$8L-- z3_3=zEmeK4dR~x)QQ@&$c3*KnuaRr6i+S;9?WNjJo}C`U^HfSo_v>5>@7eF(0%LF4 zz&oiu8G=;U&m+fk;ZQ7!A^Sx!$O4K)~a2E?EzJEU(n#;uEngR_`eJHbiH9^Vwylz;3Pr zEIe-9D@ZJWUF3?+67cjAG1z6wLa@++-AXdmqa^**k0RC67E*UeN~qFPvH|^0P`9h< zcBG(nC#`K{v~*g-yS{8cLVwnWceS+jNNTr1m2Hq!8`>qQ6-#xgIxMwTTz|bP2CY)X zTh1^rkWMoVW15wbRaM547Hh$h*K1{3=u;Nh$QqAb=C3$al0n2KY{me#U@Hbu!4QTq zf>Bg4h8nhEJI1lY9PC(j*BH8yJK1UE^{Jexb>?{Pw2`0IkD6CII~Ani{`>t@;=?^G J55a%4^aoV8#NGe^ delta 479 zcmX>TcPEiF8KeSff=Zu1<2<}q?cW;s= zP)dP;LFq_FYGR6*v9uFV?hX)}WdH^ECb9!vz$gObt7PPsRPfcmXAlGm>;MYv$jMJm zJeaUU2WY_oAU`fQv7&&Xp3wy;Zvo^hCsxIhvhO>B&l z&oRoX>VXZ>V-#lK2g?AJ07XE`9T@b$A}nnBlLeUUIW^fBfI+hms4s%4Ve%a&i^&qq zj*Oa{qnM)^RV}#kxNdOEa945P;PK#T$EU@&f!~dP2LCAm8G#-_A;F~0_gG#F zZ}ye+;NBdo`hlHMZ?d1R1q%ZoqtxUsU4_Z(bZ< -Created by FontForge 20170805 at Fri Aug 10 18:09:07 2018 +Created by FontForge 20170805 at Fri Aug 10 18:42:51 2018 By ondra The Fork Awesome font is licensed under the SIL OFL 1.1 (http://scripts.sil.org/OFL). Fork Awesome is a fork based of off Font Awesome 4.7.0 by Dave Gandy. More info on licenses at https://forkawesome.github.io @@ -19,10 +19,10 @@ The Fork Awesome font is licensed under the SIL OFL 1.1 (http://scripts.sil.org/ panose-1="2 0 5 3 0 0 0 0 0 0" ascent="1536" descent="-256" - bbox="-0.14014 -256.168 2048 1536.01" + bbox="-0.202124 -256.168 2048 1536.16" underline-thickness="89.6" underline-position="-179.2" - unicode-range="U+0020-F129" + unicode-range="U+0020-F12B" /> - + - - - - - - - - - - - - - - + - - - - diff --git a/public/fonts/fa-dtbl-1.ttf b/public/fonts/fa-dtbl-1.ttf index 36204acbf82b3fd7c6282ffb8b3f24697064ab3f..e58cb696c27e740bb1085b6b9888275fffb21ff6 100644 GIT binary patch delta 799 zcmYLHOK1~O6uoycnMpgzB-1o$8JjlgXEHTuEzza}+7BwF3SvPKsh@UC(-uta)JCZy zCV~rfA;N4Fq#%e0by4W1eipGPC?cq!RZ$S@PFyH-Q`;GD(uI%r;he*{_rCY;{ehdu za)1Effjl^%zqj|`zRT~Hs{vXs5L>hVz?Q_&o0G2r@G#+_)VOYZuM5}!%rtR(Q)jbb z*v?J>IG&Ntj_Ol}ZBry@%@THvX3mX#Yh5IbjRQ3L#?tz5aBD0?+80{Mv9WYc7jN@h zC|D&Cjbr24=^6t>!V828nTeGC_R-5QC3r#j#JE0fz$M&Gx<)vBN*_<(%3S{opzfd~ z+l`5-Y}cDZhXCTm0@q5HqYGx{bYalDV+91BYyeB0gHwTzq7@MDAj$m`L{CxSG zAPdKZCvMq&&Hch7dv1ss@sIb4_p`6dXZRMSgtSoMny+Pl`g4rEZUgV6Dr5*#`XG-S z&o$IXo3OaIV!PC&M3oLqq92`Q$o+_LHaItllHghYZGET+iDmwvr8YSn4P3s#di8a6 z1p6I>R=snjT3v;Z&*faQ9tK!GQi;!=ip|kVMq@Ot5EV5BlPuY8dEi- zT0OF&$XHOLwOH``t)5!?ruqJc-#oUNJ7XG)GKl8ISeV5a#?6`7N4Lk&jr8djBcq>6 ko7s4p=gt_J34Pf76mN+jb!zdqi~SGpA7JVH-x!m^KNOb1NdN!< delta 455 zcmbOcyCSNdfsuiMftR6yftew|%`L>Y<(fzKQI*K*L0U0xB7~B^7+{83cj+9YFq$oc!d( zg9$ryfEFA8^5b$7D+(Cu8C`(#7C^p2USe+Q%$&a83=C>dfR?oPUz@V)F zRPz|@IiLsaL*50&^V@u7;ARJEV_>*GIa3)z%VaA5fBWwr2Ll@@95@)5K*B%(}(H`$I+mQjCl45K}#CL04V2o?h6moPR=)?l)joWkVDsJVF=Q#7Nh1y>%| z4Q?6kD()LR9z1P4H+cQ{wD>mgyYbK9KP4a|&?6`$n6z1o<+bqUnGzn{n^&rQU}w~u yJWI!dg@KPzYVtK5g~`8kZcKiln>^V|PgjY75g4K%SApEeaCHqMm_~RYQyBm{&ToML diff --git a/public/fonts/fa-dtbl-1.woff2 b/public/fonts/fa-dtbl-1.woff2 index 4956c12636fb4e599db24d085e30b92328cb46e8..e70226a0703a11f92972a988c1ce966ab0d9de85 100644 GIT binary patch literal 5964 zcmV-S7qjShPew8T0RR9102fRE4FCWD04|sS02cKC0RR9100000000000000000000 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 ut2REgA0I0PUCh&u;^V;i9)Go$u;veLl( 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 diff --git a/resources/assets/fa-config/wanted.ini b/resources/assets/fa-config/wanted.ini index e4820ed..b460844 100644 --- a/resources/assets/fa-config/wanted.ini +++ b/resources/assets/fa-config/wanted.ini @@ -44,6 +44,7 @@ undo # Used in table editor spinner paper-plane-o # save proposal +upload # Upload a file # dark mode sun-o diff --git a/resources/assets/js/components/ColumnEditor.vue b/resources/assets/js/components/ColumnEditor.vue index 64143da..74a1214 100644 --- a/resources/assets/js/components/ColumnEditor.vue +++ b/resources/assets/js/components/ColumnEditor.vue @@ -5,7 +5,12 @@ Complex animated column editor for the table edit page