From bb8bc459dc6ac01c40c9a7e717da433a7ab8f8e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 5 Aug 2018 14:45:43 +0200 Subject: [PATCH] stub of the row editor --- _json_typehints.php | 17 +++ app/Http/Controllers/TableController.php | 29 ---- app/Http/Controllers/TableEditController.php | 66 ++++++++++ app/Models/BaseModel.php | 4 +- app/Models/Revision.php | 4 +- app/Models/Row.php | 2 +- app/Models/Table.php | 33 +++-- app/Providers/AppServiceProvider.php | 11 +- app/Tables/Changeset.php | 124 ++++++++++++++++-- app/Tables/Column.php | 96 ++++++++++++-- app/helpers.php | 4 + public/fonts/fa-dtbl-1-preview.html | 120 +++++++++++------ public/fonts/fa-dtbl-1.css | 39 +++--- public/fonts/fa-dtbl-1.eot | Bin 9984 -> 10520 bytes public/fonts/fa-dtbl-1.svg | 51 ++++--- public/fonts/fa-dtbl-1.ttf | Bin 9804 -> 10340 bytes public/fonts/fa-dtbl-1.woff2 | Bin 4996 -> 5108 bytes resources/assets/js/app.js | 1 + resources/assets/js/components/RowEditor.vue | 86 ++++++++++++ resources/assets/sass/_helpers.scss | 9 ++ resources/assets/sass/app.scss | 2 + .../bootstrap-customizations/_border.scss | 20 +++ .../sass/bootstrap-customizations/_nav.scss | 0 .../sass/bootstrap-customizations/_table.scss | 9 ++ resources/views/table/_rows.blade.php | 7 +- ...ade.php => _view-action-buttons.blade.php} | 40 ++---- resources/views/table/conf.blade.php | 3 +- .../views/table/propose/add-rows.blade.php | 6 + .../views/table/propose/edit-rows.blade.php | 43 ++++++ .../views/table/propose/layout.blade.php | 58 ++++++++ .../table/propose/manage-columns.blade.php | 6 + .../views/table/propose/review.blade.php | 6 + resources/views/table/view.blade.php | 2 +- routes/web.php | 3 + 34 files changed, 725 insertions(+), 176 deletions(-) create mode 100644 _json_typehints.php create mode 100644 app/Http/Controllers/TableEditController.php create mode 100644 resources/assets/js/components/RowEditor.vue create mode 100644 resources/assets/sass/bootstrap-customizations/_nav.scss create mode 100644 resources/assets/sass/bootstrap-customizations/_table.scss rename resources/views/table/{_action-buttons.blade.php => _view-action-buttons.blade.php} (60%) create mode 100644 resources/views/table/propose/add-rows.blade.php create mode 100644 resources/views/table/propose/edit-rows.blade.php create mode 100644 resources/views/table/propose/layout.blade.php create mode 100644 resources/views/table/propose/manage-columns.blade.php create mode 100644 resources/views/table/propose/review.blade.php diff --git a/_json_typehints.php b/_json_typehints.php new file mode 100644 index 0000000..7021d45 --- /dev/null +++ b/_json_typehints.php @@ -0,0 +1,17 @@ +tables()->where('name', $table)->first(); - if ($tableModel === null) abort(404, "No such table."); - - $session_key = "proposal_{$tableModel->id}"; - - /** @var Changeset $changeset */ - $changeset = $request->session()->remember($session_key, function () use ($tableModel) { - $changeset = new Changeset(); - $changeset->table = $tableModel; - $changeset->revision = $tableModel->revision; - return $changeset; - }); - - $revision = $changeset->revision; - $columns = Column::columnsFromJson($revision->columns); - $rows = $revision->rowsData($columns)->paginate(25, []); - - return view('table.propose', [ - 'table' => $tableModel, - 'revision' => $revision, - 'columns' => $columns, - 'rows' => $rows, - 'changeset' => $changeset, - ]); - } - public function delete(Request $request, User $user, string $table) { /** @var Table $tableModel */ diff --git a/app/Http/Controllers/TableEditController.php b/app/Http/Controllers/TableEditController.php new file mode 100644 index 0000000..9d4d484 --- /dev/null +++ b/app/Http/Controllers/TableEditController.php @@ -0,0 +1,66 @@ +id}"; + + if (Input::has('reset')) { + session()->forget($session_key); + } + + /** @var Changeset $changeset */ + return session()->remember($session_key, function () use ($table) { + $changeset = new Changeset(); + $changeset->table = $table; + $changeset->revision = $table->revision; + return $changeset; + }); + } + + public function draft(User $user, string $table, $tab = null) + { + /** @var Table $tableModel */ + $tableModel = $user->tables()->where('name', $table)->first(); + 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"); + + $changeset = $this->getChangeset($tableModel); + + return $this->{camel_case($tab)}($changeset); + } + + private function editRows(Changeset $changeset) + { + $revision = $changeset->revision; + $columns = $changeset->transformColumns(); + $rows = $revision->rowsData($columns, true, false)->paginate(25, []); + + return view('table.propose.edit-rows', [ + 'changeset' => $changeset, + 'table' => $changeset->table, + 'columns' => collect($columns), + 'rows' => $rows, + ]); + } +} diff --git a/app/Models/BaseModel.php b/app/Models/BaseModel.php index 8561357..a7fb450 100644 --- a/app/Models/BaseModel.php +++ b/app/Models/BaseModel.php @@ -26,7 +26,9 @@ class BaseModel extends Model public function getRelationValue($key) { if ($this->exists && !method_exists($this, $key)) { - throw new \LogicException("No attribute or relation ".var_export($key, true)); + if (!isset($this->original[$key])) { + throw new \LogicException("No attribute or relation " . var_export($key, true)); + } } return parent::getRelationValue($key); diff --git a/app/Models/Revision.php b/app/Models/Revision.php index b140623..550c31d 100644 --- a/app/Models/Revision.php +++ b/app/Models/Revision.php @@ -40,12 +40,12 @@ class Revision extends BaseModel * @param Column[] $columns * @return \Illuminate\Database\Query\Builder|static */ - public function rowsData($columns, $withId=true) + public function rowsData($columns, $withId=true, $named=true) { $selects = $withId ? ["data->>'_id' as _id"] : []; foreach ($columns as $col) { - $selects[] = "data->>'$col->id' as $col->name"; + $selects[] = "data->>'$col->id' as " . ($named ? $col->name : $col->id); } return $this->rows()->select([])->selectRaw(implode(', ', $selects)); diff --git a/app/Models/Row.php b/app/Models/Row.php index 1b7220c..ca00961 100644 --- a/app/Models/Row.php +++ b/app/Models/Row.php @@ -6,7 +6,7 @@ namespace App\Models; * Row in a data table * * @property int $id - * @property string $data - JSONB, always containing _id + * @property object|\RowData $data - JSONB, always containing _id */ class Row extends BaseModel { diff --git a/app/Models/Table.php b/app/Models/Table.php index 454d121..f5c351b 100644 --- a/app/Models/Table.php +++ b/app/Models/Table.php @@ -22,7 +22,9 @@ use Illuminate\Database\Eloquent\Collection; * @property string $origin * @property int $visits * @property-read string $viewRoute + * @property-read string $draftRoute * @property-read string $settingsRoute + * @property-read string $deleteRoute * @property-read User $owner * @property-read Table $parentTable * @property-read Table[]|Collection $forks @@ -123,21 +125,32 @@ class Table extends BaseModel public function __get($name) { - if ($name == 'viewRoute') { - return route('table.view', ['user' => $this->cachedOwner()->name, 'table' => $this->name]); - } - - if ($name == 'settingsRoute') { - return route('table.conf', ['user' => $this->cachedOwner()->name, 'table' => $this->name]); - } - - if ($name == 'deleteRoute') { - return route('table.delete', ['user' => $this->cachedOwner()->name, 'table' => $this->name]); + if (ends_with($name, 'Route')) { + $arg = [ + 'user' => $this->cachedOwner()->name, + 'table' => $this->name + ]; + + switch ($name) { + case 'viewRoute': return route('table.view', $arg); + case 'settingsRoute': return route('table.conf', $arg); + case 'draftRoute': return route('table.draft', $arg); + case 'deleteRoute': return route('table.delete', $arg); + } } return parent::__get($name); } + public function getDraftRoute($tab=null) + { + return route('table.draft', [ + 'user' => $this->cachedOwner()->name, + 'table' => $this->name, + 'tab' => $tab, + ]); + } + public function scopeForList(Builder $query) { return $query->with('revision:id,row_count')->with('owner:id,name,title') diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 44d8fb8..d01dda5 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -29,8 +29,17 @@ class AppServiceProvider extends ServiceProvider }); \Blade::directive('tooltip', function($arg) { + $arg = trim($arg); + $placement = ''; + if (starts_with($arg, ['top,', 'bottom,', 'left,', 'right,'])) { + list($placement, $arg) = explode(',', $arg); + $arg = trim($arg); + } $arge = e($arg); - return 'aria-label="' . $arge . '" title="' . $arge . '"'; + + $html = ''; + if ($placement) $html .= 'data-placement="' . $placement . '" '; + return $html . 'data-toggle="tooltip" aria-label="' . $arge . '" title="' . $arge . '"'; }); \Blade::directive('sr', function($arg) { diff --git a/app/Tables/Changeset.php b/app/Tables/Changeset.php index 2bcde12..cc61ce0 100644 --- a/app/Tables/Changeset.php +++ b/app/Tables/Changeset.php @@ -40,39 +40,43 @@ class Changeset * Rows whose content changed, identified by _id. * Only changed values are to be filled. Columns are identified by GCIDs * - * @var array|null - [[_id:…, …], …] + * Key'd by _id + * + * @var array|null - [_id -> [_id:…, cid:…, cid:…], …] */ - public $rowUpdates; + public $rowUpdates = []; /** * New rows in the full Row::data format, including GRIDs. * Values are identified by GCIDs from previously defined, or new columns. * - * @var array|null - [[_id:…, …], …] + * @var array|null - [[_id:…, cid:…, cid:…], …] */ - public $newRows; + public $newRows = []; /** * Rows to be removed * * @var int[]|null - GRIDs */ - public $removedRows; + public $removedRows = []; /** * Values changed in column specifications, such as name, title, etc. * This does not affect the table rows in any way. * - * @var array[] - column specification objects, with GCIDs + * Key'd by id + * + * @var array[] - column specification objects, with GCIDs, key'd by CID */ - public $columnUpdates; + public $columnUpdates = []; /** * New columns in the full format, including GCIDs * * @var array|null - [[id:…, …], …] */ - public $newColumns; + public $newColumns = []; /** * When reordering columns, here is the column IDs array @@ -84,7 +88,7 @@ class Changeset * * @var string[]|null - GCIDs */ - public $columnOrder; + public $columnOrder = []; /** * Columns to be removed @@ -94,7 +98,10 @@ class Changeset * * @var int[]|null - GCIDs */ - public $removedColumns; + public $removedColumns = []; + + /** @var Column[] - loaded and transformed columns, cached from previous call to transformColumns() */ + private $cachedColumns; private function walkProps() { @@ -146,6 +153,11 @@ class Changeset return $object; } + /** + * Check if there is any change in this changeset + * + * @return bool - any found + */ public function hasAnyChanges() { foreach ($this->walkProps() as $prop) { @@ -156,4 +168,96 @@ class Changeset return false; } + + /** + * Decorate / transform a single row for the editor view + * + * @param object|\DecoratedRow $row - row, must be key'd by column ids + * @param bool $decorate - to add extra underscored info for the editor + * @return \DecoratedRow|object|null - null if not decorating and the row was removed + */ + public function transformRow($row, $decorate) + { + if ($decorate) { + $row->_remove = false; + $row->_changed = []; + $row->_orig = []; + } + + // Removed rows + if (in_array($row->_id, $this->removedRows)) { + if ($decorate) { + $row->_remove = true; + } else { + return null; + } + } + + // Changed values + if (isset($this->rowUpdates[$row->_id])) { + $newVals = $this->rowUpdates[$row->_id]; + + if ($decorate) { + $row->_changed = array_keys($newVals); + $row->_orig = array_only((array)$row, $row->_changed); + } + + $row = (object)array_merge((array)$row, $newVals); + } + + // Drop deleted columns + if (!$decorate) { + foreach ($this->removedColumns as $colId) { + unset($row->$colId); + } + } + + unset($row->_row_pivot); + + return $row; + } + + /** + * Decorate / transform columns (loaded from the source revision) + * + * @return Column[] + */ + public function transformColumns() + { + if ($this->cachedColumns) return $this->cachedColumns; + $columns = Column::columnsFromJson($this->revision->columns); + + // Modify columns + $byId = []; + foreach ($columns as $column) { + $byId[$column->id] = $column; + + if (isset($this->columnUpdates[$column->id])) { + $column->modifyByChangeset($this->columnUpdates[$column->id]); + } + + if (in_array($column->id, $this->removedColumns)) { + $column->markForRemoval(); + } + } + + // Append new columns + foreach ($this->newColumns as $newColumn) { + $columns[] = $c =new Column($newColumn); + $c->markAsNew(); + } + + // Reorder + $newOrder = []; + foreach ($this->columnOrder as $id) { + $newOrder[] = $byId[$id]; + } + + $leftover_keys = array_diff(array_keys($byId), $this->columnOrder); + foreach ($leftover_keys as $id) { + $newOrder[] = $byId[$id]; + } + + return $this->cachedColumns = $newOrder; + } } diff --git a/app/Tables/Column.php b/app/Tables/Column.php index 7be9660..1434153 100644 --- a/app/Tables/Column.php +++ b/app/Tables/Column.php @@ -1,9 +1,8 @@ toRemove = true; + } + + /** + * Mark this column as new + */ + public function markAsNew() + { + $this->isNew = true; + } + + /** + * Modify by a changeset + * + * @param array $columnObject + */ + public function modifyByChangeset(array $columnObject) + { + foreach ((array)$columnObject as $key => $value) { + if ($value != $this->$key) { + $this->modified_attribs[] = $key; + $this->orig_attribs[] = $this->$key; + $this->$key = $value; + } + } + } + + public function __get($name) + { + if (property_exists($this, $name)) { + return $this->$name; + } + + if (ends_with($name, '_modified')) { + $basename = str_replace('_modified', '', $name); + if (property_exists($this, $basename)) { + return in_array($basename, $this->modified_attribs); + } + } + + if (ends_with($name, '_orig')) { + $basename = str_replace('_orig', '', $name); + if (property_exists($this, $basename)) { + return $this->orig_attribs[$basename]; + } + } + + throw new NotApplicableException("No such column property: $name"); + } + + /** + * @param $columns + * @return Column[] + */ public static function columnsFromJson($columns) { if (is_string($columns)) { @@ -73,15 +154,6 @@ class Column implements JsonSerializable $this->title = $b->title ?: $b->name; } - public function __get($name) - { - if (property_exists($this, $name)) { - return $this->$name; - } - - throw new NotApplicableException("No such column property: $name"); - } - /** * @return array with keys {name, title, type} */ diff --git a/app/helpers.php b/app/helpers.php index 178ffa1..b0159ee 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -85,6 +85,10 @@ function old_json($name, $default) { // Safe JSON funcs function toJSON($object) { + if (!$object instanceof JsonSerializable && $object instanceof \Illuminate\Contracts\Support\Arrayable) { + $object = $object->toArray(); + } + return \GuzzleHttp\json_encode($object, JSON_UNESCAPED_SLASHES + JSON_UNESCAPED_UNICODE); } diff --git a/public/fonts/fa-dtbl-1-preview.html b/public/fonts/fa-dtbl-1-preview.html index 60afadf..41e09ca 100644 --- a/public/fonts/fa-dtbl-1-preview.html +++ b/public/fonts/fa-dtbl-1-preview.html @@ -175,6 +175,7 @@ .fa-google:before, .fa-history:before, .fa-home:before, +.fa-hourglass:before, .fa-inbox:before, .fa-key-modern:before, .fa-link:before, @@ -187,7 +188,9 @@ .fa-star-o:before, .fa-table:before, .fa-th-list:before, +.fa-times:before, .fa-trash-o:before, +.fa-undo:before, .fa-user:before, .fa-user-circle-o:before, .fa-user-plus:before, @@ -221,24 +224,27 @@ .fa-google:before { content: "\f10b"; } .fa-history:before { content: "\f10c"; } .fa-home:before { content: "\f10d"; } -.fa-inbox:before { content: "\f10e"; } -.fa-key-modern:before { content: "\f10f"; } -.fa-link:before { content: "\f110"; } -.fa-pencil:before { content: "\f111"; } -.fa-plus:before { content: "\f112"; } -.fa-question-circle:before { content: "\f113"; } -.fa-sign-in:before { content: "\f114"; } -.fa-sign-out:before { content: "\f115"; } -.fa-star:before { content: "\f116"; } -.fa-star-o:before { content: "\f117"; } -.fa-table:before { content: "\f118"; } -.fa-th-list:before { content: "\f119"; } -.fa-trash-o:before { content: "\f11a"; } -.fa-user:before { content: "\f11b"; } -.fa-user-circle-o:before { content: "\f11c"; } -.fa-user-plus:before { content: "\f11d"; } -.fa-users:before { content: "\f11e"; } -.fa-wrench:before { content: "\f11f"; } +.fa-hourglass:before { content: "\f10e"; } +.fa-inbox:before { content: "\f10f"; } +.fa-key-modern:before { content: "\f110"; } +.fa-link:before { content: "\f111"; } +.fa-pencil:before { content: "\f112"; } +.fa-plus:before { content: "\f113"; } +.fa-question-circle:before { content: "\f114"; } +.fa-sign-in:before { content: "\f115"; } +.fa-sign-out:before { content: "\f116"; } +.fa-star:before { content: "\f117"; } +.fa-star-o:before { content: "\f118"; } +.fa-table:before { content: "\f119"; } +.fa-th-list:before { content: "\f11a"; } +.fa-times:before { content: "\f11b"; } +.fa-trash-o:before { content: "\f11c"; } +.fa-undo:before { content: "\f11d"; } +.fa-user:before { content: "\f11e"; } +.fa-user-circle-o:before { content: "\f11f"; } +.fa-user-plus:before { content: "\f120"; } +.fa-users:before { content: "\f121"; } +.fa-wrench:before { content: "\f122"; } @@ -254,7 +260,7 @@
-

fa-dtbl-1 contains 32 glyphs:

+

fa-dtbl-1 contains 35 glyphs:

Toggle Preview Characters
@@ -444,6 +450,19 @@
+
+
+ PpPpPpPpPpPpPpPpPpPp +
+
+ 12141618212436486072 +
+
+ + +
+
+
PpPpPpPpPpPpPpPpPpPp @@ -453,7 +472,7 @@
- +
@@ -466,7 +485,7 @@
- +
@@ -479,7 +498,7 @@
- +
@@ -492,7 +511,7 @@
- +
@@ -505,7 +524,7 @@
- +
@@ -518,7 +537,7 @@
- +
@@ -531,7 +550,7 @@
- +
@@ -544,7 +563,7 @@
- +
@@ -557,7 +576,7 @@
- +
@@ -570,7 +589,7 @@
- +
@@ -583,7 +602,7 @@
- +
@@ -596,7 +615,21 @@
- + +
+ + +
+
+ PpPpPpPpPpPpPpPpPpPp +
+
+ 12141618212436486072 +
+
+ + +
@@ -609,7 +642,20 @@
- + +
+ + +
+
+ PpPpPpPpPpPpPpPpPpPp +
+
+ 12141618212436486072 +
+
+ +
@@ -622,7 +668,7 @@
- +
@@ -635,7 +681,7 @@
- +
@@ -648,7 +694,7 @@
- +
@@ -661,7 +707,7 @@
- +
@@ -674,7 +720,7 @@
- +
diff --git a/public/fonts/fa-dtbl-1.css b/public/fonts/fa-dtbl-1.css index 2a98041..c375860 100644 --- a/public/fonts/fa-dtbl-1.css +++ b/public/fonts/fa-dtbl-1.css @@ -52,21 +52,24 @@ .fa-google::before { content: "\f10b"; } .fa-history::before { content: "\f10c"; } .fa-home::before { content: "\f10d"; } -.fa-inbox::before { content: "\f10e"; } -.fa-key-modern::before { content: "\f10f"; } -.fa-link::before { content: "\f110"; } -.fa-pencil::before { content: "\f111"; } -.fa-plus::before { content: "\f112"; } -.fa-question-circle::before { content: "\f113"; } -.fa-sign-in::before { content: "\f114"; } -.fa-sign-out::before { content: "\f115"; } -.fa-star::before { content: "\f116"; } -.fa-star-o::before { content: "\f117"; } -.fa-table::before { content: "\f118"; } -.fa-th-list::before { content: "\f119"; } -.fa-trash-o::before { content: "\f11a"; } -.fa-user::before { content: "\f11b"; } -.fa-user-circle-o::before { content: "\f11c"; } -.fa-user-plus::before { content: "\f11d"; } -.fa-users::before { content: "\f11e"; } -.fa-wrench::before { content: "\f11f"; } +.fa-hourglass::before { content: "\f10e"; } +.fa-inbox::before { content: "\f10f"; } +.fa-key-modern::before { content: "\f110"; } +.fa-link::before { content: "\f111"; } +.fa-pencil::before { content: "\f112"; } +.fa-plus::before { content: "\f113"; } +.fa-question-circle::before { content: "\f114"; } +.fa-sign-in::before { content: "\f115"; } +.fa-sign-out::before { content: "\f116"; } +.fa-star::before { content: "\f117"; } +.fa-star-o::before { content: "\f118"; } +.fa-table::before { content: "\f119"; } +.fa-th-list::before { content: "\f11a"; } +.fa-times::before, .fa-close::before { content: "\f11b"; } +.fa-trash-o::before { content: "\f11c"; } +.fa-undo::before { content: "\f11d"; } +.fa-user::before { content: "\f11e"; } +.fa-user-circle-o::before { content: "\f11f"; } +.fa-user-plus::before { content: "\f120"; } +.fa-users::before { content: "\f121"; } +.fa-wrench::before { content: "\f122"; } diff --git a/public/fonts/fa-dtbl-1.eot b/public/fonts/fa-dtbl-1.eot index 71ba15c9aff0698f1d15cb6712f4467917f0d623..20ac8fb8ebdb9e510c01fba21303987d79a86f56 100644 GIT binary patch delta 892 zcmaJ)pMZ-s#k7cAa{4cYbVs%zc=pP7LycYE;O4$ef>7a&Ea927wY7 z5+c|w@j)U&qPHH_gAWm5^&$kl6%tWBL@)VN5F%Uun@ADT!}*`{`}qIP;hZyfX7wCf zSOqX#xy{oNoU5w@mM+ydg>1l=Ef$jjk-^bkCOf!z;<032@hNC^BbhSr{PnG5S9%x zW#tjBP$G$$*-t?rfSPG-B03aaa;~gWz&hbzBs>#?89YgP6XDXyaAf4-^Vf|4QjGR* zibdmz&ReIq0OUvHxeG`x8r5~1-b>~aKfq)l0^sf9z5ata{VkQ^fYqEF=sAq!YePv5>J;^fuHMMd2{YyZSWv&{I#5bh>$|XO&9Kc? za2wnn@8;L|U1P|&V*F})nc1DWm?dQ;vL0sr6ck~{+?rfvriEF$x-=!QKpP)}E=qJ; zi!qNaFO%dJ^!OV6t(?D>bCe03!NwKj{-b7m6f72DH=xx)eUa4M5cKppYigW*o?t_> zRHSG24r2!ox;iXEz#`0PkV?R>^o9aGu6CO!+S*+`fl#mFKa6AHPZK0fx&8bs-Bo&r zS!ZrTIX!Hi8Cl7}Q>jDQr$m2Jz^F_P5}lqJn+V6_ kYETYYG7{sFk+>l-6^<*eC^J1dtUi|O)emxk>90@s3y}=XAOHXW delta 498 zcmbOc)ZoX)pw7VHqc)MvjOCX7WA}*;t@Ve@3K$sF3>X*~Wc-8mjS?=78m^g&%g}SuL0z9q~}zoiJiW1 z5-9%!XxxO1)Wj4qrMfJj+#Mh`%K!@SO=MRFnk53{t7PPsRMcNs!vN$k?f?o*$jMJm zte;fb12kX;knfe7SW&=G%IE@=w*c}L@)C1XV-B1(0y0a0_FEL>7nhWlMHB+f0y(;h zff1+*h}|FC--_qA`O3h}4isQuxZW+b9Y+6u`|lqI0~<&s2LltsDdpSzP&kHj^Fdi1#?2Gu z)z}$LCht(w;V{v)&^0nJw3uwGt}vNLy^v95a-F&k3j-gc$mDhE5|huUw@r@Gh+t -Created by FontForge 20170805 at Sat Aug 4 10:56:23 2018 +Created by FontForge 20170805 at Sun Aug 5 14:30:22 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 @@ -22,7 +22,7 @@ The Fork Awesome font is licensed under the SIL OFL 1.1 (http://scripts.sil.org/ bbox="-0.14014 -256.168 2048 1536.01" underline-thickness="89.6" underline-position="-179.2" - unicode-range="U+0020-F11F" + unicode-range="U+0020-F122" /> - + - - - - - - - - - - - - + - + - - - - diff --git a/public/fonts/fa-dtbl-1.ttf b/public/fonts/fa-dtbl-1.ttf index 922505025bc07b4e50ff4167e682227baa623105..3ec4f7969651dde9578ce0d202a6eea2036ef2bd 100644 GIT binary patch delta 851 zcmaJ!KLE@(<*+nivfSQ4?h7uDEQga4_kgyd zm=OU{jwBYp1_1Y@kd&T@j!XCLtB+7%9pgYmT8zOWIg7jx_wm|fP%rr8~BP`j%AUi!MMuWVT- z=n}f8x?h~kZR^`JTk3f(iBFP81r2~6PC+j!I!#r?sHv?HtZl^QY4Nr*-Uh~2!!fj( zsW|)(Te8U+4BU>tV8_&zLThutHEgf1w-37l&8#H8_`UK_ z(BJRqH1oW<)6wq_4$0nwFb(V%LFSSn#3u1E^V`%qwF0&HUq(IA2sRc?BeA-?ESe7D zaaOQsjuVrSW(l>>;-zmV1<|<&MlIZ=;D@VMIIQcK965re>dVPpno(#OuVSd=TvvjvA-r#G@Kg zLj+Q*m@Id+tQ?)6o0^g0aV2dD8cGt=k#L+&%t>+C5vAs5CzRioCIJXew+aUbn*)4$ MPKthinASpn054O^KmY&$ delta 449 zcmaD7aK@*efsuiMftR6yftew|%`L>Y<&aqc1B03YP*lc0Sl=k&LiQR42F3^=KOs3c zvEY%g=zj(VCJ&&PS8`d20)sV6J_7^u6remydSY?G|NlUf7}PX?e2(;-$~3Xl7fu4@ zp8$=Ukdd00BBoTA1(dr3#AX>8sr89`6WNu4hKT?LR5Ef)DlV*H0J0f(0QnPg@{<$m zCsp3mf8-XnWVN)Vl-!00jpG*Y{w|es53c+(VkI$@*KvD z$s9~NOsox)?UeHbvzq*nRttM zfA9f=X7d;3QohZ)!ZDnid1ZANH{X?0V`ns(%%Y|PBn{POFse*GrKTgpz{e=UD9R|t zD9$LsD9I?rD9tDXbbuVAJfp&73H7$gE7T*{*-MHNi!*d53uzckcGeK%hC5wqI{?jR BYtR4y diff --git a/public/fonts/fa-dtbl-1.woff2 b/public/fonts/fa-dtbl-1.woff2 index 855516621b8b0b872094bc04bc2a23fa062df914..f58599be77e8f4d12eaca623f6da1111633eb820 100644 GIT binary patch literal 5108 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 WFE2n$W+Ny|$fQ=$n_BuNXAS^65wd0g literal 4996 zcmV-~6MO7;Pew8T0RR910271&4FCWD047WT023?#0RR9100000000000000000000 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 O2j-W}_acL7HUIz&_sn + + + + + + + + + + + + + + + + + + + +
{{col.title}}
+ + + + + + + +
+ + + + + diff --git a/resources/assets/sass/_helpers.scss b/resources/assets/sass/_helpers.scss index 42e4cff..c18f61c 100644 --- a/resources/assets/sass/_helpers.scss +++ b/resources/assets/sass/_helpers.scss @@ -16,3 +16,12 @@ .box-shadow { box-shadow: 0 2px 3px rgba(black, .3); } + +.strike { + text-decoration: line-through; +} + +// for busy loaders etc +.opacity-fade { + transition: opacity .3s ease-in-out; +} diff --git a/resources/assets/sass/app.scss b/resources/assets/sass/app.scss index 1b0a595..e0c2512 100644 --- a/resources/assets/sass/app.scss +++ b/resources/assets/sass/app.scss @@ -20,6 +20,8 @@ html { @import "bootstrap-customizations/button"; @import "bootstrap-customizations/responsive"; @import "bootstrap-customizations/typography"; +@import "bootstrap-customizations/nav"; +@import "bootstrap-customizations/table"; .bio-table { td { diff --git a/resources/assets/sass/bootstrap-customizations/_border.scss b/resources/assets/sass/bootstrap-customizations/_border.scss index 67bb404..25ccb19 100644 --- a/resources/assets/sass/bootstrap-customizations/_border.scss +++ b/resources/assets/sass/bootstrap-customizations/_border.scss @@ -15,3 +15,23 @@ .border-2 { border-width: 2px !important; } + +.rounded-top-0 { + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important; +} + +.rounded-left-0 { + border-top-left-radius: 0 !important; + border-bottom-left-radius: 0 !important; +} + +.rounded-right-0 { + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} + +.rounded-bottom-0 { + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} diff --git a/resources/assets/sass/bootstrap-customizations/_nav.scss b/resources/assets/sass/bootstrap-customizations/_nav.scss new file mode 100644 index 0000000..e69de29 diff --git a/resources/assets/sass/bootstrap-customizations/_table.scss b/resources/assets/sass/bootstrap-customizations/_table.scss new file mode 100644 index 0000000..532da54 --- /dev/null +++ b/resources/assets/sass/bootstrap-customizations/_table.scss @@ -0,0 +1,9 @@ +.table-fixed { + table-layout: fixed; +} + +.td-va-middle { + td, th { + vertical-align: middle !important; + } +} diff --git a/resources/views/table/_rows.blade.php b/resources/views/table/_rows.blade.php index e71908a..3a59768 100644 --- a/resources/views/table/_rows.blade.php +++ b/resources/views/table/_rows.blade.php @@ -4,24 +4,23 @@ @php /** @var object[] $columns */ + /** @var \App\Tables\Changeset[] $changeset */ /** @var \App\Models\Row[] $rows */ @endphp - @foreach($columns as $col) - + @endforeach @foreach($rows as $row) - @foreach($columns as $col) - + @endforeach @endforeach diff --git a/resources/views/table/_action-buttons.blade.php b/resources/views/table/_view-action-buttons.blade.php similarity index 60% rename from resources/views/table/_action-buttons.blade.php rename to resources/views/table/_view-action-buttons.blade.php index f026f42..84785f7 100644 --- a/resources/views/table/_action-buttons.blade.php +++ b/resources/views/table/_view-action-buttons.blade.php @@ -9,21 +9,17 @@ diff --git a/resources/views/table/conf.blade.php b/resources/views/table/conf.blade.php index 032de80..757dec4 100644 --- a/resources/views/table/conf.blade.php +++ b/resources/views/table/conf.blade.php @@ -17,8 +17,7 @@

{{ $table->title }}

- + @icon(fa-table, sr:Back to Table) diff --git a/resources/views/table/propose/add-rows.blade.php b/resources/views/table/propose/add-rows.blade.php new file mode 100644 index 0000000..157dd53 --- /dev/null +++ b/resources/views/table/propose/add-rows.blade.php @@ -0,0 +1,6 @@ +@php($tab='add-rows') +@extends('table.propose.layout') + +@section('tab-content') + ... +@stop diff --git a/resources/views/table/propose/edit-rows.blade.php b/resources/views/table/propose/edit-rows.blade.php new file mode 100644 index 0000000..1ac4791 --- /dev/null +++ b/resources/views/table/propose/edit-rows.blade.php @@ -0,0 +1,43 @@ +@php + $tab = 'edit-rows'; + /** @var \App\Tables\Column[] $columns */ + /** @var \App\Tables\Changeset $changeset */ + /** @var \App\Models\Row[]|Illuminate\Pagination\Paginator $rows */ + /** @var \App\Models\Table $table */ +@endphp + +@extends('table.propose.layout') + +@section('tab-content') + + @if($rows->hasPages()) +
+ +
+ @endif + +
+ @php + $transformed = $rows->keyBy('_id')->map(function($r) use ($changeset) { + /** @var \App\Tables\Changeset $changeset */ + return $changeset->transformRow($r, true); + }); + @endphp + +
_id{{$col->name}} ("{{ $col->title }}") [ {{$col->id}} ]{{ $col->title }}
{{ $row->_id }}{{ $row->{$col->name} }}{{ $row->{$col->name} }}
+
+ + + @if($rows->hasPages()) +
+ +
+ @endif +@stop diff --git a/resources/views/table/propose/layout.blade.php b/resources/views/table/propose/layout.blade.php new file mode 100644 index 0000000..ee8c2af --- /dev/null +++ b/resources/views/table/propose/layout.blade.php @@ -0,0 +1,58 @@ +{{-- Basic table view --}} + +@extends('layouts.app') + +@php +/** @var \App\Models\Table $table */ + +if (!isset($tab) || $tab == '') $tab = 'edit-rows'; +@endphp + +@section('content') +
+
+ + {{ $table->owner->handle }}{{-- + --}}/{{-- + --}}{{ $table->name }} + + +

{{ $table->title }}

+ + @icon(fa-close, sr:Discard) + + @if(user()->ownsTable($table)) + + @icon(fa-save fa-pr)Commit + + @else + + @icon(fa-save fa-pr)Submit + + @endif +
+
+ + + +
+ @yield('tab-content') +
{{-- End of row --}} + +@endsection diff --git a/resources/views/table/propose/manage-columns.blade.php b/resources/views/table/propose/manage-columns.blade.php new file mode 100644 index 0000000..ca34a41 --- /dev/null +++ b/resources/views/table/propose/manage-columns.blade.php @@ -0,0 +1,6 @@ +@php($tab='manage-columns') +@extends('table.propose.layout') + +@section('tab-content') + ... +@stop diff --git a/resources/views/table/propose/review.blade.php b/resources/views/table/propose/review.blade.php new file mode 100644 index 0000000..11f5d7f --- /dev/null +++ b/resources/views/table/propose/review.blade.php @@ -0,0 +1,6 @@ +@php($tab='review') +@extends('table.propose.layout') + +@section('tab-content') + ... +@stop diff --git a/resources/views/table/view.blade.php b/resources/views/table/view.blade.php index ec2ae45..aa8cdf9 100644 --- a/resources/views/table/view.blade.php +++ b/resources/views/table/view.blade.php @@ -17,7 +17,7 @@

{{ $table->title }}

- @include('table._action-buttons') + @include('table._view-action-buttons') diff --git a/routes/web.php b/routes/web.php index a33779f..c68376e 100644 --- a/routes/web.php +++ b/routes/web.php @@ -49,6 +49,9 @@ Route::group(['middleware' => ['auth', 'activated']], function () { Route::get('@{user}/{table}/settings', 'TableController@settings')->name('table.conf'); Route::post('@{user}/{table}/settings', 'TableController@storeSettings')->name('table.storeConf'); Route::post('@{user}/{table}/delete', 'TableController@delete')->name('table.delete'); + + Route::post('@{user}/{table}/draft/update', 'TableEditController@draftUpdate')->name('table.draft-update'); + Route::get('@{user}/{table}/draft/{tab?}', 'TableEditController@draft')->name('table.draft'); }); // Routes for all authed users