mirror of
https://github.com/prurigro/hypothetical.git
synced 2024-12-22 09:40:23 -05:00
Reorganize the dashboard functionality such that everything can be configured in app/Models/Dashboard.php and a given model, add support for user-bound lists, improve security, fix some style issues, and update the readme
This commit is contained in:
parent
55db186a2c
commit
a676c91370
18 changed files with 746 additions and 550 deletions
|
@ -1,6 +1,6 @@
|
|||
DEFAULT_LANGUAGE=en
|
||||
|
||||
APP_NAME='Hypothetical Template'
|
||||
APP_NAME='Hypothetical'
|
||||
APP_DESC='A website template'
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
|
|
|
@ -6,9 +6,7 @@ use File;
|
|||
use Image;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||
|
||||
use App\Models\Contact;
|
||||
use App\Models\Subscriptions;
|
||||
use App\Models\Dashboard;
|
||||
|
||||
class DashboardController extends Controller {
|
||||
|
||||
|
@ -37,61 +35,177 @@ class DashboardController extends Controller {
|
|||
/**
|
||||
* Dashboard View
|
||||
*/
|
||||
public function getContact()
|
||||
public function getView($model)
|
||||
{
|
||||
return view('dashboard.view', [
|
||||
'heading' => 'Contact Form Submissions',
|
||||
'model' => 'contact',
|
||||
'rows' => Contact::getContactSubmissions(),
|
||||
'columns' => Contact::$dashboard_columns
|
||||
]);
|
||||
}
|
||||
$model_class = Dashboard::getModel($model, 'view');
|
||||
|
||||
public function getSubscriptions()
|
||||
{
|
||||
return view('dashboard.view', [
|
||||
'heading' => 'Subscriptions',
|
||||
'model' => 'subscriptions',
|
||||
'rows' => Subscriptions::getSubscriptions(),
|
||||
'columns' => Subscriptions::$dashboard_columns
|
||||
]);
|
||||
if ($model_class != null) {
|
||||
return view('dashboard.view', [
|
||||
'heading' => $model_class::getDashboardHeading($model),
|
||||
'column_headings' => $model_class::getDashboardColumnData('headings'),
|
||||
'model' => $model,
|
||||
'rows' => $model_class::getDashboardData(),
|
||||
'columns' => $model_class::$dashboard_columns
|
||||
]);
|
||||
} else {
|
||||
abort(404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dashboard Edit
|
||||
* Dashboard Edit List
|
||||
*/
|
||||
public function getEditList($model)
|
||||
{
|
||||
$model_class = Dashboard::getModel($model, 'edit');
|
||||
|
||||
if ($model_class != null) {
|
||||
return view('dashboard.edit-list', [
|
||||
'heading' => $model_class::getDashboardHeading($model),
|
||||
'model' => $model,
|
||||
'rows' => $model_class::getDashboardData(),
|
||||
'display' => $model_class::$dashboard_display,
|
||||
'button' => $model_class::$dashboard_button,
|
||||
'sortcol' => $model_class::$dashboard_reorder ? $model_class::$dashboard_sort_column : false,
|
||||
'create' => $model_class::$create,
|
||||
'delete' => $model_class::$delete,
|
||||
'filter' => $model_class::$filter,
|
||||
'export' => $model_class::$export
|
||||
]);
|
||||
} else {
|
||||
abort(404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dashboard Edit Item
|
||||
*/
|
||||
public function getEditItem($model, $id = 'new')
|
||||
{
|
||||
$model_class = Dashboard::getModel($model, 'edit');
|
||||
|
||||
if ($model_class != null) {
|
||||
if ($id == 'new') {
|
||||
$item = null;
|
||||
} else {
|
||||
if ($model_class::where('id', $id)->exists()) {
|
||||
$item = $model_class::find($id);
|
||||
|
||||
if (is_null($item) || !$item->userCheck()) {
|
||||
return view('errors.no-such-record');
|
||||
}
|
||||
} else {
|
||||
return view('errors.no-such-record');
|
||||
}
|
||||
}
|
||||
|
||||
return view('dashboard.edit-item', [
|
||||
'heading' => $model_class::getDashboardHeading($model),
|
||||
'model' => $model,
|
||||
'id' => $id,
|
||||
'item' => $item,
|
||||
'help_text' => $model_class::$dashboard_help_text,
|
||||
'columns' => $model_class::$dashboard_columns
|
||||
]);
|
||||
} else {
|
||||
abort(404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dashboard Export: Export data as a spreadsheet
|
||||
*/
|
||||
public function getExport($model)
|
||||
{
|
||||
// set the filename of the spreadsheet
|
||||
$filename = preg_replace([ '/\ /', '/[^a-z0-9\-]/' ], [ '-', '' ], strtolower(env('APP_NAME'))) . '-' . $model . '-' . date('m-d-Y');
|
||||
$model_class = Dashboard::getModel($model);
|
||||
|
||||
// set the model using the 'model' request argument
|
||||
switch ($model) {
|
||||
case 'contact':
|
||||
$headings = [ 'Date', 'Name', 'Email', 'Message' ];
|
||||
$items = Contact::select('created_at', 'name', 'email', 'message')->get()->toArray();
|
||||
break;
|
||||
case 'subscriptions':
|
||||
$headings = [ 'Date', 'Email', 'Name' ];
|
||||
$items = Subscriptions::select('created_at', 'email', 'name')->get()->toArray();
|
||||
break;
|
||||
default:
|
||||
abort(404);
|
||||
if ($model_class != null && $model_class::$export) {
|
||||
$filename = preg_replace([ '/\ /', '/[^a-z0-9\-]/' ], [ '-', '' ], strtolower(env('APP_NAME'))) . '-' . $model . '-' . date('m-d-Y');
|
||||
$headings = $model_class::getDashboardColumnData('headings', false);
|
||||
$items = $model_class::select($model_class::getDashboardColumnData('names', false))->get()->toArray();
|
||||
array_unshift($items, $headings);
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$spreadsheet->getActiveSheet()->getDefaultColumnDimension()->setWidth(25);
|
||||
$spreadsheet->getActiveSheet()->fromArray($items, NULL, 'A1');
|
||||
$writer = new Xlsx($spreadsheet);
|
||||
header('Content-Type: application/vnd.ms-excel');
|
||||
header('Content-Disposition: attachment;filename="' . $filename . '"');
|
||||
header('Cache-Control: max-age=0');
|
||||
$writer->save('php://output');
|
||||
} else {
|
||||
abort(404);
|
||||
}
|
||||
}
|
||||
|
||||
array_unshift($items, $headings);
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$spreadsheet->getActiveSheet()->getDefaultColumnDimension()->setWidth(25);
|
||||
$spreadsheet->getActiveSheet()->fromArray($items, NULL, 'A1');
|
||||
$writer = new Xlsx($spreadsheet);
|
||||
header('Content-Type: application/vnd.ms-excel');
|
||||
header('Content-Disposition: attachment;filename="' . $filename . '"');
|
||||
header('Cache-Control: max-age=0');
|
||||
$writer->save('php://output');
|
||||
/**
|
||||
* Dashboard Reorder: Reorder rows
|
||||
*/
|
||||
public function postReorder(Request $request)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'order' => 'required',
|
||||
'column' => 'required',
|
||||
'model' => 'required'
|
||||
]);
|
||||
|
||||
$model_class = Dashboard::getModel($request['model'], 'edit');
|
||||
|
||||
if ($model_class != null) {
|
||||
$order = $request['order'];
|
||||
$column = $request['column'];
|
||||
|
||||
// update each row with the new order
|
||||
foreach (array_keys($order) as $order_id) {
|
||||
$item = $model_class::find($order_id);
|
||||
$item->$column = $order[$order_id];
|
||||
$item->save();
|
||||
}
|
||||
|
||||
return 'success';
|
||||
} else {
|
||||
return 'model-access-fail';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dashboard Update: Create and update rows
|
||||
*/
|
||||
public function postUpdate(Request $request)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'id' => 'required',
|
||||
'model' => 'required',
|
||||
'columns' => 'required'
|
||||
]);
|
||||
|
||||
$model_class = Dashboard::getModel($request['model'], 'edit');
|
||||
|
||||
if ($model_class != null) {
|
||||
if ($request['id'] == 'new') {
|
||||
$item = new $model_class;
|
||||
} else {
|
||||
$item = $model_class::find($request['id']);
|
||||
|
||||
if (is_null($item)) {
|
||||
return 'record-access-fail';
|
||||
} else if (!$item->userCheck()) {
|
||||
return 'permission-fail';
|
||||
}
|
||||
}
|
||||
|
||||
// populate the eloquent object with the remaining items in $request
|
||||
foreach ($request['columns'] as $column) {
|
||||
$item->$column = $request[$column];
|
||||
}
|
||||
|
||||
// save the new or updated item
|
||||
$item->save();
|
||||
|
||||
// return the id number in the format '^id:[0-9][0-9]*$' on success
|
||||
return 'id:' . $item->id;
|
||||
} else {
|
||||
return 'model-access-fail';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,16 +219,28 @@ class DashboardController extends Controller {
|
|||
'name' => 'required'
|
||||
]);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
$directory = base_path() . '/public/uploads/' . $request['model'] . '/img/';
|
||||
file::makeDirectory($directory, 0755, true, true);
|
||||
$image = Image::make($request->file('file'));
|
||||
$image->save($directory . $request['id'] . '-' . $request['name'] . '.jpg');
|
||||
} else {
|
||||
return 'file-upload-fail';
|
||||
}
|
||||
$model_class = Dashboard::getModel($request['model'], 'edit');
|
||||
|
||||
return 'success';
|
||||
if ($model_class != null) {
|
||||
$item = $model_class::find($request['id']);
|
||||
|
||||
if (is_null($item)) {
|
||||
return 'record-access-fail';
|
||||
} else if (!$item->userCheck()) {
|
||||
return 'permission-fail';
|
||||
} else if ($request->hasFile('file')) {
|
||||
$directory = base_path() . '/public/uploads/' . $request['model'] . '/img/';
|
||||
file::makeDirectory($directory, 0755, true, true);
|
||||
$image = Image::make($request->file('file'));
|
||||
$image->save($directory . $request['id'] . '-' . $request['name'] . '.jpg');
|
||||
} else {
|
||||
return 'file-upload-fail';
|
||||
}
|
||||
|
||||
return 'success';
|
||||
} else {
|
||||
return 'model-access-fail';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -129,77 +255,27 @@ class DashboardController extends Controller {
|
|||
'ext' => 'required'
|
||||
]);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
$directory = base_path() . '/public/uploads/' . $request['model'] . '/files/';
|
||||
file::makeDirectory($directory, 0755, true, true);
|
||||
$request->file('file')->move($directory, $request['id'] . '-' . $request['name'] . '.' . $request['ext']);
|
||||
$model_class = Dashboard::getModel($request['model'], 'edit');
|
||||
|
||||
if ($model_class != null) {
|
||||
$item = $model_class::find($request['id']);
|
||||
|
||||
if (is_null($item)) {
|
||||
return 'record-access-fail';
|
||||
} else if (!$item->userCheck()) {
|
||||
return 'permission-fail';
|
||||
} else if ($request->hasFile('file')) {
|
||||
$directory = base_path() . '/public/uploads/' . $request['model'] . '/files/';
|
||||
file::makeDirectory($directory, 0755, true, true);
|
||||
$request->file('file')->move($directory, $request['id'] . '-' . $request['name'] . '.' . $request['ext']);
|
||||
} else {
|
||||
return 'file-upload-fail';
|
||||
}
|
||||
|
||||
return 'success';
|
||||
} else {
|
||||
return 'file-upload-fail';
|
||||
return 'model-access-fail';
|
||||
}
|
||||
|
||||
return 'success';
|
||||
}
|
||||
|
||||
/**
|
||||
* Dashboard Edit: Create and edit rows
|
||||
*/
|
||||
public function postEdit(Request $request)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'id' => 'required',
|
||||
'model' => 'required',
|
||||
'columns' => 'required'
|
||||
]);
|
||||
|
||||
// store the id request variable for easy access
|
||||
$id = $request['id'];
|
||||
|
||||
// set the model using the 'model' request argument
|
||||
switch ($request['model']) {
|
||||
default:
|
||||
return 'model-access-fail';
|
||||
}
|
||||
|
||||
// populate the eloquent object with the remaining items in $request
|
||||
foreach ($request['columns'] as $column) {
|
||||
$item->$column = $request[$column];
|
||||
}
|
||||
|
||||
// save the new or updated item
|
||||
$item->save();
|
||||
|
||||
// return the id number in the format '^id:[0-9][0-9]*$' on success
|
||||
return 'id:' . $item->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dashboard Reorder: Reorder rows
|
||||
*/
|
||||
public function postReorder(Request $request)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'order' => 'required',
|
||||
'column' => 'required',
|
||||
'model' => 'required'
|
||||
]);
|
||||
|
||||
$order = $request['order'];
|
||||
$column = $request['column'];
|
||||
|
||||
// set the model using the 'model' request argument
|
||||
switch ($request['model']) {
|
||||
default:
|
||||
return 'model-access-fail';
|
||||
}
|
||||
|
||||
// update each row with the new order
|
||||
foreach (array_keys($order) as $order_id) {
|
||||
$item = $items::find($order_id);
|
||||
$item->$column = $order[$order_id];
|
||||
$item->save();
|
||||
}
|
||||
|
||||
return 'success';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -212,38 +288,42 @@ class DashboardController extends Controller {
|
|||
'model' => 'required'
|
||||
]);
|
||||
|
||||
// set the model using the 'model' request argument
|
||||
switch ($request['model']) {
|
||||
default:
|
||||
return 'model-access-fail';
|
||||
}
|
||||
$model_class = Dashboard::getModel($request['model'], 'edit');
|
||||
|
||||
// delete the row with the id using the 'id' request argument
|
||||
if ($items::where('id', $request['id'])->exists()) {
|
||||
$items::where('id', $request['id'])->delete();
|
||||
} else {
|
||||
return 'row-delete-fail';
|
||||
}
|
||||
if ($model_class != null) {
|
||||
$item = $model_class::find($request['id']);
|
||||
|
||||
// delete associated files if they exist
|
||||
foreach ($items::$dashboard_columns as $column) {
|
||||
if ($column['type'] == 'image') {
|
||||
$image = base_path() . '/public/uploads/' . $request['model'] . '/img/' . $request['id'] . '-' . $column['name'] . '.jpg';
|
||||
if (is_null($item)) {
|
||||
return 'record-access-fail';
|
||||
} else if (!$item->userCheck()) {
|
||||
return 'permission-fail';
|
||||
}
|
||||
|
||||
if (file_exists($image) && !unlink($image)) {
|
||||
return 'image-delete-fail';
|
||||
}
|
||||
} else if ($column['type'] == 'file') {
|
||||
$file = base_path() . '/public/uploads/' . $request['model'] . '/files/' . $request['id'] . '-' . $column['name'] . '.' . $column['ext'];
|
||||
// delete the row
|
||||
$item->delete();
|
||||
|
||||
if (file_exists($file) && !unlink($file)) {
|
||||
return 'file-delete-fail';
|
||||
// delete associated files if they exist
|
||||
foreach ($model_class::$dashboard_columns as $column) {
|
||||
if ($column['type'] == 'image') {
|
||||
$image = base_path() . '/public/uploads/' . $request['model'] . '/img/' . $request['id'] . '-' . $column['name'] . '.jpg';
|
||||
|
||||
if (file_exists($image) && !unlink($image)) {
|
||||
return 'image-delete-fail';
|
||||
}
|
||||
} else if ($column['type'] == 'file') {
|
||||
$file = base_path() . '/public/uploads/' . $request['model'] . '/files/' . $request['id'] . '-' . $column['name'] . '.' . $column['ext'];
|
||||
|
||||
if (file_exists($file) && !unlink($file)) {
|
||||
return 'file-delete-fail';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return a success
|
||||
return 'success';
|
||||
// Return a success
|
||||
return 'success';
|
||||
} else {
|
||||
return 'model-access-fail';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -257,15 +337,26 @@ class DashboardController extends Controller {
|
|||
'name' => 'required'
|
||||
]);
|
||||
|
||||
$image = base_path() . '/public/uploads/' . $request['model'] . '/img/' . $request['id'] . '-' . $request['name'] . '.jpg';
|
||||
$model_class = Dashboard::getModel($request['model'], 'edit');
|
||||
|
||||
if (!file_exists($image)) {
|
||||
return 'image-not-exists-fail';
|
||||
} else if (!unlink($image)) {
|
||||
return 'image-delete-fail';
|
||||
if ($model_class != null) {
|
||||
$image = base_path() . '/public/uploads/' . $request['model'] . '/img/' . $request['id'] . '-' . $request['name'] . '.jpg';
|
||||
$item = $model_class::find($request['id']);
|
||||
|
||||
if (is_null($item)) {
|
||||
return 'record-access-fail';
|
||||
} else if (!$item->userCheck()) {
|
||||
return 'permission-fail';
|
||||
} else if (!file_exists($image)) {
|
||||
return 'image-not-exists-fail';
|
||||
} else if (!unlink($image)) {
|
||||
return 'image-delete-fail';
|
||||
}
|
||||
|
||||
return 'success';
|
||||
} else {
|
||||
return 'model-access-fail';
|
||||
}
|
||||
|
||||
return 'success';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -280,15 +371,26 @@ class DashboardController extends Controller {
|
|||
'ext' => 'required'
|
||||
]);
|
||||
|
||||
$file = base_path() . '/public/uploads/' . $request['model'] . '/files/' . $request['id'] . '-' . $request['name'] . '.' . $request['ext'];
|
||||
$model_class = Dashboard::getModel($request['model'], 'edit');
|
||||
|
||||
if (!file_exists($file)) {
|
||||
return 'file-not-exists-fail';
|
||||
} else if (!unlink($file)) {
|
||||
return 'file-delete-fail';
|
||||
if ($model_class != null) {
|
||||
$file = base_path() . '/public/uploads/' . $request['model'] . '/files/' . $request['id'] . '-' . $request['name'] . '.' . $request['ext'];
|
||||
$item = $model_class::find($request['id']);
|
||||
|
||||
if (is_null($item)) {
|
||||
return 'record-access-fail';
|
||||
} else if (!$item->userCheck()) {
|
||||
return 'permission-fail';
|
||||
} else if (!file_exists($file)) {
|
||||
return 'file-not-exists-fail';
|
||||
} else if (!unlink($file)) {
|
||||
return 'file-delete-fail';
|
||||
}
|
||||
|
||||
return 'success';
|
||||
} else {
|
||||
return 'model-access-fail';
|
||||
}
|
||||
|
||||
return 'success';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
25
app/Models/Blog.php
Normal file
25
app/Models/Blog.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Blog extends DashboardModel
|
||||
{
|
||||
protected $table = 'blog';
|
||||
|
||||
public static $dashboard_type = 'edit';
|
||||
|
||||
public static $dashboard_help_text = '<strong>NOTE</strong>: Tags should be separated by semicolons';
|
||||
|
||||
public static $dashboard_display = [ 'title', 'created_at' ];
|
||||
|
||||
public static $dashboard_columns = [
|
||||
[ 'name' => 'user_id', 'type' => 'user' ],
|
||||
[ 'name' => 'created_at', 'title' => 'Date', 'type' => 'display' ],
|
||||
[ 'name' => 'title', 'type' => 'text' ],
|
||||
[ 'name' => 'body', 'type' => 'mkd' ],
|
||||
[ 'name' => 'tags', 'type' => 'text' ],
|
||||
[ 'name' => 'header-image', 'title' => 'Header Image', 'type' => 'image', 'delete' => true ]
|
||||
];
|
||||
}
|
|
@ -4,34 +4,18 @@ namespace App\Models;
|
|||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Contact extends Model
|
||||
class Contact extends DashboardModel
|
||||
{
|
||||
/**
|
||||
* The contact table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'contact';
|
||||
|
||||
/**
|
||||
* Dashboard columns
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $dashboard_columns = [
|
||||
[ 'Date', 'created_at' ],
|
||||
[ 'Name', 'name' ],
|
||||
[ 'Email', 'email' ],
|
||||
[ 'Message', 'message' ]
|
||||
];
|
||||
public static $dashboard_heading = 'Contact Form Submissions';
|
||||
|
||||
/**
|
||||
* Returns the list of all contact submissions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getContactSubmissions()
|
||||
{
|
||||
return self::orderBy('created_at', 'desc')->get();
|
||||
}
|
||||
public static $export = true;
|
||||
|
||||
public static $dashboard_columns = [
|
||||
[ 'name' => 'created_at', 'title' => 'Date' ],
|
||||
[ 'name' => 'name' ],
|
||||
[ 'name' => 'email' ],
|
||||
[ 'name' => 'message' ]
|
||||
];
|
||||
}
|
||||
|
|
58
app/Models/Dashboard.php
Normal file
58
app/Models/Dashboard.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class Dashboard
|
||||
{
|
||||
/**
|
||||
* Dashboard Menu
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static $menu = [
|
||||
[
|
||||
'title' => 'Blog',
|
||||
'type' => 'edit',
|
||||
'model' => 'blog'
|
||||
],
|
||||
|
||||
[
|
||||
'title' => 'Form Submissions',
|
||||
|
||||
'submenu' => [
|
||||
[
|
||||
'title' => 'Contact',
|
||||
'type' => 'view',
|
||||
'model' => 'contact'
|
||||
],
|
||||
[
|
||||
'title' => 'Subscriptions',
|
||||
'type' => 'view',
|
||||
'model' => 'subscriptions'
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* Retrieve a Dashboard Model
|
||||
*
|
||||
* @return model
|
||||
*/
|
||||
public static function getModel($model, $type = null)
|
||||
{
|
||||
$model_name = ucfirst($model);
|
||||
|
||||
if (file_exists(app_path() . '/Models/' . $model_name . '.php')) {
|
||||
$model_class = 'App\\Models\\' . ucfirst($model);
|
||||
|
||||
if ($type != null && $type != $model_class::$dashboard_type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $model_class;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class DashboardMenu
|
||||
{
|
||||
/**
|
||||
* Dashboard Menu
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static $menu = [
|
||||
[
|
||||
'title' => 'Submissions',
|
||||
|
||||
'submenu' => [
|
||||
[
|
||||
'title' => 'Contact',
|
||||
'type' => 'view',
|
||||
'model' => 'contact'
|
||||
],
|
||||
[
|
||||
'title' => 'Subscriptions',
|
||||
'type' => 'view',
|
||||
'model' => 'subscriptions'
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
171
app/Models/DashboardModel.php
Normal file
171
app/Models/DashboardModel.php
Normal file
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Auth;
|
||||
|
||||
class DashboardModel extends Model
|
||||
{
|
||||
/*
|
||||
* The dashboard page type
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $dashboard_type = 'view';
|
||||
|
||||
/*
|
||||
* Dashboard heading
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $dashboard_heading = null;
|
||||
|
||||
/*
|
||||
* Whether the model can be exported
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public static $export = false;
|
||||
|
||||
/*
|
||||
* Whether new rows can be created
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public static $create = true;
|
||||
|
||||
/*
|
||||
* Whether new rows can be deleted
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public static $delete = true;
|
||||
|
||||
/*
|
||||
* Whether rows can be filtered
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public static $filter = true;
|
||||
|
||||
/*
|
||||
* Dashboard help text
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $dashboard_help_text = '';
|
||||
|
||||
/*
|
||||
* Array of columns to display in the dashboard edit list
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $dashboard_display = [];
|
||||
|
||||
/**
|
||||
* Whether to allow click-and-drag reordering
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public static $dashboard_reorder = false;
|
||||
|
||||
/**
|
||||
* The dashboard sort column
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $dashboard_sort_column = 'created_at';
|
||||
|
||||
/**
|
||||
* The dashboard sort direction (only when $dashboard_reorder == false)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $dashboard_sort_direction = 'desc';
|
||||
|
||||
/**
|
||||
* The dashboard buttons
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $dashboard_button = [];
|
||||
|
||||
/**
|
||||
* Returns the dashboard heading
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getDashboardHeading($model)
|
||||
{
|
||||
return static::$dashboard_heading == null ? ucfirst($model) : static::$dashboard_heading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of column 'headings' or 'names'
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getDashboardColumnData($type, $all_columns = true)
|
||||
{
|
||||
$column_data = [];
|
||||
|
||||
foreach (static::$dashboard_columns as $column) {
|
||||
if ($all_columns || !array_key_exists('type', $column) || !preg_match('/^(hidden|user|image|file)$/', $column['type'])) {
|
||||
if ($type == 'headings') {
|
||||
if (array_key_exists('title', $column)) {
|
||||
array_push($column_data, $column['title']);
|
||||
} else {
|
||||
array_push($column_data, ucfirst($column['name']));
|
||||
}
|
||||
} else if ($type == 'names') {
|
||||
array_push($column_data, $column['name']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $column_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns data for the dashboard
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getDashboardData()
|
||||
{
|
||||
$sort_direction = static::$dashboard_reorder ? 'desc' : static::$dashboard_sort_direction;
|
||||
$query = self::orderBy(static::$dashboard_sort_column, 'desc');
|
||||
|
||||
foreach (static::$dashboard_columns as $column) {
|
||||
if (array_key_exists('type', $column) && $column['type'] == 'user') {
|
||||
$query->where($column['name'], Auth::id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $query->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a user column exists and whether it matches the current user if it does
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function userCheck() {
|
||||
$user_check = true;
|
||||
|
||||
foreach (static::$dashboard_columns as $column) {
|
||||
if (array_key_exists('type', $column) && $column['type'] == 'user') {
|
||||
if ($this->{$column['name']} != Auth::id()) {
|
||||
$user_check = false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $user_check;
|
||||
}
|
||||
}
|
|
@ -4,33 +4,15 @@ namespace App\Models;
|
|||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Subscriptions extends Model
|
||||
class Subscriptions extends DashboardModel
|
||||
{
|
||||
/**
|
||||
* The subscriptions table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'subscriptions';
|
||||
|
||||
/**
|
||||
* Dashboard columns
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $dashboard_columns = [
|
||||
[ 'Date', 'created_at' ],
|
||||
[ 'Email', 'email' ],
|
||||
[ 'Name', 'name' ]
|
||||
];
|
||||
public static $export = true;
|
||||
|
||||
/**
|
||||
* Returns the list of all subscriptions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getSubscriptions()
|
||||
{
|
||||
return self::orderBy('created_at', 'desc')->get();
|
||||
}
|
||||
public static $dashboard_columns = [
|
||||
[ 'title' => 'Date', 'name' => 'created_at' ],
|
||||
[ 'name' => 'email' ],
|
||||
[ 'name' => 'name' ]
|
||||
];
|
||||
}
|
||||
|
|
36
database/migrations/2018_04_17_222542_add_blog_table.php
Normal file
36
database/migrations/2018_04_17_222542_add_blog_table.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddBlogTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('blog', function(Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('user_id')->unsigned();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
$table->string('title')->nullable();
|
||||
$table->text('body')->nullable();
|
||||
$table->text('tags')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop('blog');
|
||||
}
|
||||
}
|
341
readme.md
341
readme.md
|
@ -54,283 +54,96 @@ Other information about database interaction, routing, controllers, etc can be v
|
|||
|
||||
## Dashboard
|
||||
|
||||
Unless otherwise stated all examples in this section are to be added to `app/Http/Controllers/DashboardController.php`.
|
||||
### Updating the dashboard menu
|
||||
|
||||
### Adding a Viewable Model to the Dashboard
|
||||
The dashboard menu can be edited by changing the `$menu` array in `app/Models/Dashboard.php`.
|
||||
|
||||
#### Viewable List of Rows
|
||||
The each item in the array is itself an array, containing either a menu item or a dropdown of menu items.
|
||||
|
||||
First add a function to generate the page:
|
||||
Dropdowns should contain the following keys:
|
||||
|
||||
```php
|
||||
public function getContact()
|
||||
{
|
||||
return view('dashboard.view', [
|
||||
'heading' => 'Contact Form Submissions',
|
||||
'model' => 'contact',
|
||||
'rows' => Contact::getContactSubmissions(),
|
||||
'columns' => Contact::$dashboard_columns
|
||||
]);
|
||||
}
|
||||
```
|
||||
* `title`: The text that appears on the dropdown item
|
||||
* `submenu`: This is an array of menu items.
|
||||
|
||||
* `heading`: The title that will appear for this page
|
||||
* `model`: The model that will be accessed on this page
|
||||
* `rows`: A function returning an array containing the data to be shown on this page
|
||||
* `columns`: Expects a variable called `$dashboard_columns` in the respective model that contains an array:
|
||||
Menu items should contain the following keys:
|
||||
|
||||
* `title`: The text that appears on the menu item
|
||||
* `type`: The dashboard type (this can be `view` for a viewable table or `edit` for an editable list)
|
||||
* `model`: The lowercase name of the database model
|
||||
|
||||
### Adding a new model to the dashboard
|
||||
|
||||
Create a model that extends the `DashboardModel` class and override variables that don't fit the defaults.
|
||||
|
||||
#### DashboardModel variables
|
||||
|
||||
* `$dashboard_type`: The dashboard type (this can be `view` for a viewable table or `edit` for an editable list)
|
||||
* `$dashboard_heading`: This sets the heading that appears on the dashboard page; not setting this will use the model name
|
||||
* `$export`: This enables a button that allows the table to be exported as a spreadsheet
|
||||
|
||||
##### Edit variables
|
||||
|
||||
These are variables that only function when the `$dashboard_type` variable is set to `edit`.
|
||||
|
||||
* `$create`: A boolean determining whether to enable a button that allows new records to be created
|
||||
* `$delete`: A boolean determining whether to enable a button that allows records to be deleted
|
||||
* `$filter`: A boolean determining whether to enable an input field that allows records to be searched
|
||||
* `$dashboard_help_text`: An html string that will add a help box to the top of the edit-item page
|
||||
* `$dashboard_display`: An array to configure what column data to show on each item in the edit-list
|
||||
* `$dashboard_reorder`: A boolean determining whether to render drag handles to reorder the items in the list
|
||||
* `$dashboard_sort_column`: A string containing the column used to sort the list (this should be an `integer` when `$dashboard_reorder` is true)
|
||||
* `$dashboard_sort_direction`: When `$dashboard_reorder` is false this determines the sort direction (this can be `desc` for descending or `asc` ascending)
|
||||
* `$dashboard_button`: An array containing the following items in this order:
|
||||
* The title
|
||||
* Confirmation text asking the user to confirm
|
||||
* A "success" message to display when the response is `success`
|
||||
* A "failure" message to display when the response is not `success`
|
||||
* The URL to send the POST request to with the respective `id` in the request variable
|
||||
|
||||
##### Configuring the columns
|
||||
|
||||
All `DashboardModel` models require a `$dashboard_columns` array that declares which columns to show and how to treat them.
|
||||
|
||||
All models use the following attributes:
|
||||
|
||||
* `name`: The name of the model
|
||||
* `title`: (optional) The title that should be associated with the model; when unset this becomes the model name with its first letter capitalized
|
||||
|
||||
Models with their `$dashboard_type` set to `edit` also use:
|
||||
|
||||
* `type`: The column type which can be any of the following:
|
||||
* `text`: Text input field for text data
|
||||
* `mkd`: Markdown editor for text data containing markdown
|
||||
* `date`: Date and time selection tool for date/time data
|
||||
* `select`: Text input via option select with possible options in an `options` array
|
||||
* `hidden`: Fields that will contain values to pass to the update function but won't appear on the page (this must be used for the sort column)
|
||||
* `image`: Fields that contain image uploads
|
||||
* `file`: Fields that contains file uploads
|
||||
* `display`: Displayed information that can't be edited
|
||||
* `user`: This should point to a foreign key that references the id on the users table; setting this will bind items to the user that created them
|
||||
* `name`: (required by `file` and `image`) Used along with the record id to determine the filename
|
||||
* `delete`: (optional for `file` and `image`) Enables a delete button for the upload when set to true
|
||||
* `ext`: (required by `file`) Configures the file extension of the upload
|
||||
|
||||
An example of the `$dashboard_columns` array in a model with its `$dashboard_type` set to `view`:
|
||||
|
||||
```php
|
||||
public static $dashboard_columns = [
|
||||
[ 'Date', 'created_at' ],
|
||||
[ 'Name', 'name' ],
|
||||
[ 'Email', 'email' ],
|
||||
[ 'Message', 'message' ]
|
||||
[ 'title' => 'Date', 'name' => 'created_at' ],
|
||||
[ 'name' => 'email' ],
|
||||
[ 'name' => 'name' ]
|
||||
];
|
||||
```
|
||||
|
||||
### Adding an Editable Model to the Dashboard
|
||||
|
||||
#### Editable List of Rows
|
||||
|
||||
##### Editable List for Unsortable Model
|
||||
|
||||
```php
|
||||
public function getShows()
|
||||
{
|
||||
return view('dashboard.edit-list', [
|
||||
'heading' => 'Shows',
|
||||
'model' => 'shows',
|
||||
'path' => 'shows-page',
|
||||
'rows' => Shows::getShowsList(),
|
||||
'column' => 'title',
|
||||
'button' => [ 'Email Show', 'Are you sure you want to send an email?', 'Email successfully sent', 'Failed to send email', '/email-show' ],
|
||||
'sortcol' => false,
|
||||
'delete' => true,
|
||||
'create' => true,
|
||||
'export' => true,
|
||||
'filter' => true
|
||||
]);
|
||||
}
|
||||
```
|
||||
|
||||
##### Editable List for Sortable Model
|
||||
|
||||
**NOTE**: Sortable models must have an entry configured in the `postReorder` function (details below)
|
||||
|
||||
```php
|
||||
public function getNews()
|
||||
{
|
||||
return view('dashboard.edit-list', [
|
||||
'heading' => 'News',
|
||||
'model' => 'news',
|
||||
'rows' => News::getNewsList(),
|
||||
'column' => 'title',
|
||||
'button' => [ 'Email Show', 'Are you sure you want to send an email?', 'Email successfully sent', 'Failed to send email', '/email-show' ],
|
||||
'sortcol' => 'order',
|
||||
'delete' => false,
|
||||
'create' => true,
|
||||
'export' => true,
|
||||
'filter' => true
|
||||
]);
|
||||
}
|
||||
```
|
||||
|
||||
* `heading`: The title that will appear for this page
|
||||
* `model`: The model that will be accessed on this page
|
||||
* `path`: (optional) This can be used to set a different URL path than the default of the model name
|
||||
* `rows`: A function returning an array containing the data to be shown on this page
|
||||
* `column`: The column name in the array that contains the data to display in each row (an array can be used to specify multiple columns)
|
||||
* `button`: Add a button with a title, confirmation, success and error messages, and a post request path that takes an id and returns `success` on success
|
||||
* `sortcol`: The name of the column containing the sort order or `false` to disable
|
||||
* `delete`: A `delete` button will appear in the list if this is set to `true`
|
||||
* `create`: A `new` button will appear in the heading if this is set to `true`
|
||||
* `export`: An `export` button will appear in the heading if this is set to `true`
|
||||
* `filter`: An input box will appear below the heading that can filter rows by input if this is set to `true`
|
||||
|
||||
#### Editable Item
|
||||
|
||||
This function should be named the same as the one above except with `Edit` at the end
|
||||
|
||||
##### Editable Item for Unsortable Model
|
||||
|
||||
```php
|
||||
public function getShowsEdit($id = 'new')
|
||||
{
|
||||
if ($id != 'new') {
|
||||
if (Shows::where('id', $id)->exists()) {
|
||||
$item = Shows::where('id', $id)->first();
|
||||
} else {
|
||||
return view('errors.no-such-record');
|
||||
}
|
||||
} else {
|
||||
$item = null;
|
||||
}
|
||||
|
||||
return view('dashboard.edit-item', [
|
||||
'heading' => 'Shows',
|
||||
'model' => 'shows',
|
||||
'id' => $id,
|
||||
'item' => $item,
|
||||
'help_text' => '<strong>NOTE:</strong> This is some help text for the current page',
|
||||
'columns' => $dashboard_columns
|
||||
]);
|
||||
}
|
||||
```
|
||||
|
||||
##### Editable Item for Sortable Model
|
||||
|
||||
```php
|
||||
public function getNewsEdit($id = 'new')
|
||||
{
|
||||
if ($id != 'new') {
|
||||
if (News::where('id', $id)->exists()) {
|
||||
$item = News::where('id', $id)->first();
|
||||
} else {
|
||||
return view('errors.no-such-record');
|
||||
}
|
||||
} else {
|
||||
$item = new News();
|
||||
$item['order'] = News::count();
|
||||
}
|
||||
|
||||
return view('dashboard.edit-item', [
|
||||
'heading' => 'News',
|
||||
'model' => 'news',
|
||||
'id' => $id,
|
||||
'item' => $item,
|
||||
'columns' => News::$dashboard_columns
|
||||
]);
|
||||
}
|
||||
```
|
||||
|
||||
* `heading`: The title that will appear for this page
|
||||
* `model`: The model that will be accessed on this page
|
||||
* `id`: Always set this to `$id`
|
||||
* `item`: Always set this to `$item`
|
||||
* `help_text`: An optional value that will add a box containing help text above the form if set
|
||||
* `columns`: Expects a variable called `$dashboard_columns` in the respective model that contains an array:
|
||||
* `name` is the name of the column to be edited
|
||||
* `type` is the type of column (details below)
|
||||
* `label` is an optional value that overrides the visible column name
|
||||
An example of the `$dashboard_columns` array in a model with its `$dashboard_type` set to `edit`:
|
||||
|
||||
```php
|
||||
public static $dashboard_columns = [
|
||||
[ 'name' => 'title', 'type' => 'text', 'label' => 'The Title' ],
|
||||
[ 'name' => 'iframe', 'type' => 'text' ],
|
||||
[ 'name' => 'halign', 'type' => 'select', 'options' => [ 'left', 'center', 'right' ] ],
|
||||
[ 'name' => 'story', 'type' => 'mkd' ],
|
||||
[ 'label' => 'Header Image', 'name' => 'headerimage', 'type' => 'image' ],
|
||||
[ 'name' => 'order', 'type' => 'hidden' ],
|
||||
[ 'label' => 'PDF File', 'name' => 'pdf', 'type' => 'file', 'ext' => 'pdf' ]
|
||||
[ 'name' => 'user_id', 'type' => 'user' ],
|
||||
[ 'name' => 'created_at', 'title' => 'Date', 'type' => 'display' ],
|
||||
[ 'name' => 'title', 'type' => 'text' ],
|
||||
[ 'name' => 'body', 'type' => 'mkd' ],
|
||||
[ 'name' => 'tags', 'type' => 'text' ],
|
||||
[ 'name' => 'header-image', 'title' => 'Header Image', 'type' => 'image', 'delete' => true ]
|
||||
];
|
||||
```
|
||||
|
||||
###### Editable Column Types
|
||||
|
||||
The following is a list of possible `types` in the `columns` array for Editable Items:
|
||||
|
||||
* `text`: Text input field for text data
|
||||
* `mkd`: Markdown editor for text data containing markdown
|
||||
* `date`: Date and time selection tool for date/time data
|
||||
* `select`: Text input via option select with possible options in an `options` array
|
||||
* `hidden`: Fields that will contain values to pass to the update function but won't appear on the page (this must be used for the sort column)
|
||||
* `image`: Fields that contain image uploads
|
||||
* `name`: not part of the database and is instead used in the filename
|
||||
* `delete`: (optional) if true then uploaded images can be deleted
|
||||
* `file`: Fields that contains file uploads
|
||||
* `name`: not part of the database and is instead used in the filename
|
||||
* `ext` required key containing the file extension
|
||||
* `delete`: (optional) if true then uploaded files can be deleted
|
||||
* `display`: Displayed information that can't be edited
|
||||
|
||||
#### Edit Item Functionality
|
||||
|
||||
Editable models must have an entry in the switch statement of the `postEdit` function to make create and edit functionality work:
|
||||
|
||||
```php
|
||||
switch ($request['model']) {
|
||||
case 'shows':
|
||||
$item = $id == 'new' ? new Shows : Shows::find($id);
|
||||
break;
|
||||
case 'news':
|
||||
$item = $id == 'new' ? new News : News::find($id);
|
||||
break;
|
||||
default:
|
||||
return 'model-access-fail';
|
||||
}
|
||||
```
|
||||
|
||||
#### Additional Requirement for Sortable Models
|
||||
|
||||
Sortable models must have an entry in the switch statement of the `postReorder` function to make sorting functionality work:
|
||||
|
||||
```php
|
||||
switch ($request['model']) {
|
||||
case 'news':
|
||||
$items = new News();
|
||||
break;
|
||||
default:
|
||||
return 'model-access-fail';
|
||||
}
|
||||
```
|
||||
|
||||
#### Additional Requirements for Image Upload
|
||||
|
||||
If the value of `imgup` has been set to `true`, ensure `public/uploads/model_name` exists (where `model_name` is the name of the given model) and contains a `.gitkeep` that exists in version control.
|
||||
|
||||
By default, uploaded images are saved in JPEG format with the value of the `id` column of the respective row as its name and `.jpg` as its file extension.
|
||||
|
||||
When a row is deleted, its respective image will be deleted as well if it exists.
|
||||
|
||||
### Adding to the Dashboard Menu
|
||||
|
||||
Edit the `$menu` array in `app/Models/DashboardMenu.php` where the first column of each item is the title and the second is either a path, or an array of submenu items.
|
||||
|
||||
```php
|
||||
public static $menu = [
|
||||
[ 'Contact', 'contact' ],
|
||||
[ 'Subscriptions', 'subscriptions' ],
|
||||
|
||||
[
|
||||
'Projects', [
|
||||
[ 'Residential', 'projects-residential' ],
|
||||
[ 'Commercial', 'projects-commercial' ]
|
||||
]
|
||||
]
|
||||
];
|
||||
```
|
||||
|
||||
#### Additional Requirement for Delete Functionality
|
||||
|
||||
Editable models with `delete` set to `true` must have an entry in the switch statement of the `deleteDelete` function to make deletion functionality work:
|
||||
|
||||
```php
|
||||
switch ($request['model']) {
|
||||
case 'shows':
|
||||
$items = new Shows();
|
||||
break;
|
||||
case 'news':
|
||||
$items = new News();
|
||||
break;
|
||||
default:
|
||||
return 'model-access-fail';
|
||||
}
|
||||
```
|
||||
|
||||
#### Additional Requirement for Export Functionality
|
||||
|
||||
Viewable models and editable models with `export` set to `true` must have an entry in the switch statement of the `getExport` function to make the export button work:
|
||||
|
||||
```php
|
||||
switch ($model) {
|
||||
case 'contact':
|
||||
$headings = [ 'Date', 'Name', 'Email', 'Message' ];
|
||||
$items = Contact::select('created_at', 'name', 'email', 'message')->get()->toArray();
|
||||
break;
|
||||
default:
|
||||
abort(404);
|
||||
}
|
||||
```
|
||||
|
||||
* `$headings`: The visible column names in the same order as the array containing the items to be exported
|
||||
* `$items`: A function returning an array containing the data to be exported
|
||||
|
|
16
resources/assets/js/dashboard.js
vendored
16
resources/assets/js/dashboard.js
vendored
|
@ -113,15 +113,14 @@ function editListInit() {
|
|||
const editList = document.getElementById("edit-list"),
|
||||
$editList = $(editList),
|
||||
$token = $("#token"),
|
||||
model = $editList.data("model"),
|
||||
path = $editList.data("path");
|
||||
model = $editList.data("model");
|
||||
|
||||
// initialize new button functionality
|
||||
const newButtonInit = function() {
|
||||
const $newButton = $(".btn.new-button");
|
||||
|
||||
$newButton.on("click", function() {
|
||||
window.location.href = "/dashboard/" + path + "-edit/new";
|
||||
window.location.href = "/dashboard/edit-item/" + model + "/new";
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -135,7 +134,7 @@ function editListInit() {
|
|||
itemId = $listItem.data("id");
|
||||
|
||||
// go to the edit page
|
||||
window.location.href = "/dashboard/" + path + "-edit/" + itemId;
|
||||
window.location.href = "/dashboard/edit-item/" + model + "/" + itemId;
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -281,7 +280,6 @@ function editItemInit() {
|
|||
$spinner = $("#loading-modal"),
|
||||
fadeTime = 250,
|
||||
model = $editItem.data("model"),
|
||||
path = $editItem.data("path"),
|
||||
id = $editItem.data("id"),
|
||||
operation = id === "new" ? "create" : "update";
|
||||
|
||||
|
@ -363,7 +361,7 @@ function editItemInit() {
|
|||
// functionality to run on success
|
||||
const returnSuccess = function() {
|
||||
hideLoadingModal();
|
||||
window.location.href = "/dashboard/" + path;
|
||||
window.location.href = "/dashboard/edit/" + model;
|
||||
};
|
||||
|
||||
// add the file from the file upload box for file-upload class elements
|
||||
|
@ -582,10 +580,10 @@ function editItemInit() {
|
|||
if (!submitting) {
|
||||
if (changes) {
|
||||
askConfirmation("Cancel changes and return to the list?", function() {
|
||||
window.location.href = "/dashboard/" + path;
|
||||
window.location.href = "/dashboard/edit/" + model;
|
||||
});
|
||||
} else {
|
||||
window.location.href = "/dashboard/" + path;
|
||||
window.location.href = "/dashboard/edit/" + model;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -604,7 +602,7 @@ function editItemInit() {
|
|||
// submit the update
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/dashboard/edit",
|
||||
url: "/dashboard/update",
|
||||
data: formData
|
||||
}).always(function(response) {
|
||||
if (/^id:[0-9][0-9]*$/.test(response)) {
|
||||
|
|
53
resources/assets/sass/dashboard.scss
vendored
53
resources/assets/sass/dashboard.scss
vendored
|
@ -37,6 +37,7 @@ body {
|
|||
margin-bottom: $grid-gutter-width;
|
||||
border: 0;
|
||||
background-color: $c-dashboard-dark;
|
||||
user-select: none;
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
padding-right: 8px;
|
||||
|
@ -51,8 +52,13 @@ body {
|
|||
@include font-sans-bold;
|
||||
overflow: hidden;
|
||||
max-width: calc(100vw - 60px);
|
||||
color: $c-text-light;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover, &:focus, &:active {
|
||||
color: $c-text-light;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
@ -67,6 +73,45 @@ body {
|
|||
@include media-breakpoint-up(md) {
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
&-icon {
|
||||
position: relative;
|
||||
|
||||
&-bar {
|
||||
$v-inset: 6px;
|
||||
$h-inset: 3px;
|
||||
position: absolute;
|
||||
left: $h-inset;
|
||||
width: calc(100% - #{$h-inset * 2});
|
||||
height: 2px;
|
||||
background-color: $c-text-light;
|
||||
|
||||
&:nth-child(1) {
|
||||
top: $v-inset;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
bottom: $v-inset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
color: fade-out($c-text-light, 0.25);
|
||||
|
||||
&.active {
|
||||
color: $c-text-light;
|
||||
}
|
||||
|
||||
&.dropdown-toggle {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
|
@ -84,10 +129,18 @@ body {
|
|||
}
|
||||
|
||||
.dropdown-item {
|
||||
background-color: transparent;
|
||||
transition: background-color 150ms;
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
padding-right: 8px;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
&:hover, &:focus, &:active {
|
||||
background-color: fade-out(#000, 0.95);
|
||||
color: $c-text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
@extends('dashboard.core')
|
||||
|
||||
@section('dashboard-body')
|
||||
@if(!empty($help_text))
|
||||
@if($help_text != '')
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
|
@ -13,7 +13,7 @@
|
|||
</div>
|
||||
@endif
|
||||
|
||||
<form id="edit-item" class="edit-item" data-id="{{ $id }}" data-model="{{ $model }}" data-path="{{ isset($path) ? $path : $model }}">
|
||||
<form id="edit-item" class="edit-item" data-id="{{ $id }}" data-model="{{ $model }}">
|
||||
<input type="hidden" id="token" value="{{ csrf_token() }}" />
|
||||
|
||||
<div class="container-fluid">
|
||||
|
@ -23,9 +23,11 @@
|
|||
|
||||
@if($column['type'] == 'hidden')
|
||||
<input class="text-input" type="hidden" name="{{ $column['name'] }}" id="{{ $column['name'] }}" value="{{ $value }}" />
|
||||
@elseif($column['type'] == 'user')
|
||||
<input class="text-input" type="hidden" name="{{ $column['name'] }}" id="{{ $column['name'] }}" value="{{ Auth::id() }}" />
|
||||
@elseif($column['type'] != 'display' || $id != 'new')
|
||||
<div class="col-12 col-md-2">
|
||||
<label for="{{ $column['name'] }}">{{ empty($column['label']) ? ucfirst($column['name']) : $column['label'] }}:</label>
|
||||
<label for="{{ $column['name'] }}">{{ array_key_exists('title', $column) ? $column['title'] : ucfirst($column['name']) }}:</label>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-10">
|
||||
|
@ -46,13 +48,12 @@
|
|||
@endforeach
|
||||
</select>
|
||||
@elseif($column['type'] == 'image')
|
||||
<input class="image-upload" type="file" name="{{ $column['name'] }}" id="{{ $column['name'] }}" />
|
||||
|
||||
@set('current_image', "/uploads/$model/img/$id-" . $column['name'] . '.jpg')
|
||||
<input class="image-upload" type="file" name="{{ $column['name'] }}" id="{{ $column['name'] }}" />
|
||||
|
||||
@if(file_exists(base_path() . '/public' . $current_image))
|
||||
<div id="current-image-{{ $column['name'] }}">
|
||||
<img class="current-image" src="{{ $current_image }}" />
|
||||
<img class="current-image" src="{{ $current_image }}?version={{ env('CACHE_BUST') }}" />
|
||||
|
||||
@if(array_key_exists('delete', $column) && $column['delete'])
|
||||
<span class="edit-button delete image" data-name="{{ $column['name'] }}">
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<input id="filter-input" class="search" placeholder="Filter" />
|
||||
@endif
|
||||
|
||||
<ul id="edit-list" class="list-group edit-list list" data-model="{{ $model }}" data-path="{{ isset($path) ? $path : $model }}" {{ $sortcol != false ? "data-sort=$sortcol" : '' }}>
|
||||
<ul id="edit-list" class="list-group edit-list list" data-model="{{ $model }}" {{ $sortcol != false ? "data-sort=$sortcol" : '' }}>
|
||||
@foreach($rows as $row)
|
||||
<li class="list-group-item {{ $sortcol != false ? 'sortable' : '' }}" data-id="{{ $row['id'] }}">
|
||||
<div class="title-column">
|
||||
|
@ -32,23 +32,19 @@
|
|||
</div>
|
||||
@endif
|
||||
|
||||
@if(is_array($column))
|
||||
@foreach($column as $col)
|
||||
@if($row[$col] != '')
|
||||
<div class="column">{{ $row[$col] }}</div>
|
||||
@foreach($display as $display_column)
|
||||
@if($row[$display_column] != '')
|
||||
<div class="column">{{ $row[$display_column] }}</div>
|
||||
|
||||
@if(!$loop->last)
|
||||
<div class="spacer">|</div>
|
||||
@endif
|
||||
@if(!$loop->last)
|
||||
<div class="spacer">|</div>
|
||||
@endif
|
||||
@endforeach
|
||||
@else
|
||||
{{ $row[$column] }}
|
||||
@endif
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div class="button-column">
|
||||
@if(isset($button) && is_array($button))
|
||||
@if(!empty($button))
|
||||
<button type="button" class="action-button btn btn-secondary" data-confirmation="{{ $button[1] }}" data-success="{{ $button[2] }}" data-error="{{ $button[3] }}" data-url="{{ $button[4] }}">{{ $button[0] }}</button>
|
||||
@endif
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
@section('dashboard-body')
|
||||
<div class="list-group menu-list">
|
||||
@foreach(App\Models\DashboardMenu::$menu as $menu_item)
|
||||
@foreach(App\Models\Dashboard::$menu as $menu_item)
|
||||
@if(array_key_exists('submenu', $menu_item))
|
||||
@foreach($menu_item['submenu'] as $submenu_item)
|
||||
<li class="list-group-item">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<nav class="navbar navbar-expand-lg navbar-dark">
|
||||
<nav class="navbar navbar-expand-lg">
|
||||
@set('current_page', preg_replace([ '/^.*\/dashboard\/?/', '/\/.*/' ], [ '', '' ], Request::url()))
|
||||
|
||||
<a class="navbar-brand" href="{{ url('/dashboard') }}">
|
||||
|
@ -6,7 +6,11 @@
|
|||
</a>
|
||||
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#dashboard-navbar" aria-controls="dashboard-navbar" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
<span class="navbar-toggler-icon">
|
||||
<span class="navbar-toggler-icon-bar"></span>
|
||||
<span class="navbar-toggler-icon-bar"></span>
|
||||
<span class="navbar-toggler-icon-bar"></span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div id="dashboard-navbar" class="collapse navbar-collapse">
|
||||
|
@ -18,14 +22,16 @@
|
|||
<li class="nav-item"><a class="nav-link" href="{{ url('/register') }}">Register</a></li>
|
||||
@endif
|
||||
@else
|
||||
@foreach(App\Models\DashboardMenu::$menu as $menu_item)
|
||||
@foreach(App\Models\Dashboard::$menu as $menu_item)
|
||||
@if(array_key_exists('submenu', $menu_item))
|
||||
<li class="nav-item dropdown">
|
||||
<a id="menu-dropdown" class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{{ $menu_item['title'] }} <span class="caret"></span>
|
||||
</a>
|
||||
@set('dropdown_id', preg_replace([ '/\ \ */', '/[^a-z\-]/' ], [ '-', '' ], strtolower($menu_item['title'])))
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="menu-dropdown">
|
||||
<li class="nav-item dropdown">
|
||||
<span id="menu-dropdown-{{ $dropdown_id }}" class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{{ $menu_item['title'] }} <span class="caret"></span>
|
||||
</span>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="menu-dropdown-{{ $dropdown_id }}">
|
||||
@foreach($menu_item['submenu'] as $submenu_item)
|
||||
<a class="dropdown-item" href="{{ url('/dashboard/' . $submenu_item['type'] . '/' . $submenu_item['model']) }}">{{ $submenu_item['title'] }}</a>
|
||||
@endforeach
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
<table class="table">
|
||||
<thead>
|
||||
<tr class="heading-row">
|
||||
@foreach($columns as $column)
|
||||
<th>{{ $column[0] }}</th>
|
||||
@foreach($columns as $index => $column)
|
||||
<th>{{ $column_headings[$index] }}</th>
|
||||
@endforeach
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -20,8 +20,8 @@
|
|||
<tbody>
|
||||
@foreach($rows as $row)
|
||||
<tr>
|
||||
@foreach($columns as $column)
|
||||
<td><strong class="mobile-heading">{{ $column[0] }}: </strong>{{ $row[$column[1]] }}</td>
|
||||
@foreach($columns as $index => $column)
|
||||
<td><strong class="mobile-heading">{{ $column_headings[$index] }}: </strong>{{ $row[$column['name']] }}</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@endforeach
|
||||
|
|
|
@ -30,12 +30,13 @@ Route::get('/logout', 'Auth\LoginController@logout');
|
|||
|
||||
Route::group([ 'prefix' => 'dashboard' ], function() {
|
||||
Route::get('/', 'DashboardController@index');
|
||||
Route::get('/contact', 'DashboardController@getContact');
|
||||
Route::get('/subscriptions', 'DashboardController@getSubscriptions');
|
||||
Route::get('/view/{model}', 'DashboardController@getView');
|
||||
Route::get('/edit/{model}', 'DashboardController@getEditList');
|
||||
Route::get('/edit-item/{model}/{id}', 'DashboardController@getEditItem');
|
||||
Route::get('/export/{model}', 'DashboardController@getExport');
|
||||
Route::post('/image-upload', 'DashboardController@postImageUpload');
|
||||
Route::post('/file-upload', 'DashboardController@postFileUpload');
|
||||
Route::post('/edit', 'DashboardController@postEdit');
|
||||
Route::post('/update', 'DashboardController@postUpdate');
|
||||
Route::post('/reorder', 'DashboardController@postReorder');
|
||||
Route::delete('/delete', 'DashboardController@deleteDelete');
|
||||
Route::delete('/image-delete', 'DashboardController@deleteImageDelete');
|
||||
|
|
Loading…
Reference in a new issue