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 71ba15c..20ac8fb 100644 Binary files a/public/fonts/fa-dtbl-1.eot and b/public/fonts/fa-dtbl-1.eot differ diff --git a/public/fonts/fa-dtbl-1.svg b/public/fonts/fa-dtbl-1.svg index 3115101..1fd7887 100644 --- a/public/fonts/fa-dtbl-1.svg +++ b/public/fonts/fa-dtbl-1.svg @@ -1,11 +1,11 @@ -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 9225050..3ec4f79 100644 Binary files a/public/fonts/fa-dtbl-1.ttf and b/public/fonts/fa-dtbl-1.ttf differ diff --git a/public/fonts/fa-dtbl-1.woff2 b/public/fonts/fa-dtbl-1.woff2 index 8555166..f58599b 100644 Binary files a/public/fonts/fa-dtbl-1.woff2 and b/public/fonts/fa-dtbl-1.woff2 differ diff --git a/resources/assets/js/app.js b/resources/assets/js/app.js index 866d344..22eb7a3 100644 --- a/resources/assets/js/app.js +++ b/resources/assets/js/app.js @@ -68,6 +68,7 @@ $(document).on('input keypress paste keyup', 'input[data-autoalias]', function ( window.Vue = require('vue'); Vue.component('column-editor', require('./components/ColumnEditor.vue')); +Vue.component('row-editor', require('./components/RowEditor.vue')); Vue.component('v-icon', require('./components/Icon.vue')); const app = new Vue({ diff --git a/resources/assets/js/components/RowEditor.vue b/resources/assets/js/components/RowEditor.vue new file mode 100644 index 0000000..880851e --- /dev/null +++ b/resources/assets/js/components/RowEditor.vue @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + +
{{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