add option to upload file when creating a table

master
Ondřej Hruška 6 years ago
parent 7ae41b368e
commit 13b22f7cb4
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 43
      app/Http/Controllers/TableController.php
  2. 1
      app/Models/Row.php
  3. 36
      resources/assets/js/components/ColumnEditor.vue
  4. 15
      resources/views/table/create.blade.php
  5. 2
      resources/views/table/propose/add-rows-csv.blade.php

@ -81,16 +81,17 @@ class TableController extends Controller
*/ */
public function create() public function create()
{ {
$exampleData = $exampleData = "";
"Mercenaria mercenaria,hard clam,40\n" . // "Mercenaria mercenaria,hard clam,40\n" .
"Magallana gigas,pacific oyster,30\n" . // "Magallana gigas,pacific oyster,30\n" .
"Patella vulgata,common limpet,20"; // "Patella vulgata,common limpet,20";
$columns = Column::columnsFromJson([ $columns = Column::columnsFromJson([
// fake 'id' to satisfy the check in Column constructor // fake 'id' to satisfy the check in Column constructor
['id' => 1, 'name' => 'latin', 'type' => 'string', 'title' => 'Latin Name'], ['id' => 1, 'name' => 'column_1', 'type' => 'string', 'title' => 'First Column'],
['id' => 2, 'name' => 'common', 'type' => 'string', 'title' => 'Common Name'], // ['id' => 1, 'name' => 'latin', 'type' => 'string', 'title' => 'Latin Name'],
['id' => 3, 'name' => 'lifespan', 'type' => 'int', 'title' => 'Lifespan (years)'] // ['id' => 2, 'name' => 'common', 'type' => 'string', 'title' => 'Common Name'],
// ['id' => 3, 'name' => 'lifespan', 'type' => 'int', 'title' => 'Lifespan (years)']
]); ]);
return view('table.create', [ return view('table.create', [
@ -210,7 +211,33 @@ class TableController extends Controller
} }
// --- DATA --- // --- DATA ---
$dataCsvLines = Utils::csvToArray($input->data); $fname = 'csv-file';
$dataCsvLines = [];
if ($request->hasFile($fname)) {
try {
$file = $request->file($fname);
if ($file->isValid() && $file->isReadable()) {
$handle = $file->openFile();
$dataCsvLines = Utils::csvToArray($handle);
if (empty($dataCsvLines)) throw new \Exception("Failed to parse CSV file.");
$handle = null;
} else {
throw new \Exception("File not valid.");
}
} catch (\Exception $e) {
return $this->backWithErrors(['csv-file' => $e->getMessage()]);
}
}
else if ($input->data) {
try {
$text = trim($input->data);
if (!empty($text)) {
$dataCsvLines = Utils::csvToArray($text);
}
} catch (\Exception $e) {
return $this->backWithErrors(['data' => $e->getMessage()]);
}
}
// Preparing data to insert into the Rows table // Preparing data to insert into the Rows table
$rowsToInsert = null; $rowsToInsert = null;

@ -83,6 +83,7 @@ class Row extends BaseModel
*/ */
public static function allocateRowIDs($count) public static function allocateRowIDs($count)
{ {
if ($count == 0) return null;
$last = \DB::selectOne("SELECT multi_nextval('global_row_id_seq', ?) AS last_id;", [$count])->last_id; $last = \DB::selectOne("SELECT multi_nextval('global_row_id_seq', ?) AS last_id;", [$count])->last_id;
return [$last - $count + 1, $last]; return [$last - $count + 1, $last];
} }

@ -63,6 +63,9 @@ Complex animated column editor for the table edit page
<input v-model="col.name" <input v-model="col.name"
:class="['form-control', { 'is-invalid': col._errors && col._errors['name'] }]" :class="['form-control', { 'is-invalid': col._errors && col._errors['name'] }]"
:title="(col._errors && col._errors['name']) ? col._errors['name'][0] : null" :title="(col._errors && col._errors['name']) ? col._errors['name'][0] : null"
:ref="`edit-${i}-name`"
@keydown.down="verticalTab(i, 'name', 1)"
@keydown.up="verticalTab(i, 'name', -1)"
type="text"> type="text">
</td> </td>
@ -81,6 +84,9 @@ Complex animated column editor for the table edit page
<input v-model="col.title" <input v-model="col.title"
:title="(col._errors && col._errors['title']) ? col._errors['title'][0] : null" :title="(col._errors && col._errors['title']) ? col._errors['title'][0] : null"
:class="['form-control', { 'is-invalid': col._errors && col._errors['title'] }]" :class="['form-control', { 'is-invalid': col._errors && col._errors['title'] }]"
:ref="`edit-${i}-title`"
@keydown.down="verticalTab(i, 'title', 1)"
@keydown.up="verticalTab(i, 'title', -1)"
type="text"> type="text">
</td> </td>
</template> </template>
@ -141,7 +147,7 @@ Complex animated column editor for the table edit page
@media screen and (min-width: 625px) { @media screen and (min-width: 625px) {
table.new-table { table.new-table {
margin-left: -53px; margin-left: -66px;
} }
} }
@ -471,6 +477,34 @@ export default {
for (const [key, value] of Object.entries(col._loadvals)) { for (const [key, value] of Object.entries(col._loadvals)) {
col[key] = value col[key] = value
} }
},
/**
* Move to next or prev editable cell vertically
*
* @param index
* @param field
* @param dir - +1 down, -1 up
*/
verticalTab (index, field, dir) {
if (dir == -1) {
// up
for(let i = index-1; i>= 0; i--) {
if (this.columns[i]._editing || this.newTable) {
this.$refs[`edit-${i}-${field}`][0].focus()
break;
}
}
}
else {
// down
for(let i = index+1; i < this.columns.length; i++) {
if (this.columns[i]._editing || this.newTable) {
this.$refs[`edit-${i}-${field}`][0].focus()
break;
}
}
}
} }
} }
} }

@ -4,6 +4,7 @@
@section('content') @section('content')
<form method="POST" action="{{route('table.storeNew')}}" class="row justify-content-center" <form method="POST" action="{{route('table.storeNew')}}" class="row justify-content-center"
enctype="multipart/form-data"
aria-label="New Table"> aria-label="New Table">
@csrf @csrf
@ -57,11 +58,15 @@
</div> </div>
</div> </div>
{!! Widget::textarea('data', 'Initial data')->value($exampleData)->height('12em') {!! Widget::par('
->help(' Initialize the table with pasted CSV lines or an uploaded CSV file,
Initial table data in CSV format, columns corresponding to the using the column order you defined above. This is optional, you can always
specification you entered above. This is optional; you can fill the table fill or modify the table later.
later, e.g. by uploading a CSV file.') !!} ', 'text-muted') !!}
{!! Widget::textarea('data', 'CSV as text')->value($exampleData)->height('12em') !!}
{!! Widget::file('csv-file', 'CSV file')->accept("text/csv") !!}
<div class="row form-group"> <div class="row form-group">
<div class="col-md-7 offset-md-3"> <div class="col-md-7 offset-md-3">

@ -23,7 +23,7 @@
} }
@endphp @endphp
{!! Widget::par('Append rows from pasted CSV lines or uploaded CSV file') !!} {!! Widget::par('Append rows from pasted CSV lines or an uploaded CSV file') !!}
{{-- TODO interactive widget to select which cols are included, and in which order --}} {{-- TODO interactive widget to select which cols are included, and in which order --}}
{!! Widget::labeledPar('Columns', implode(', ', $cols), '', false) !!} {!! Widget::labeledPar('Columns', implode(', ', $cols), '', false) !!}

Loading…
Cancel
Save