diff --git a/database/migrations/2020_10_27_102330_create_tasks_table.php b/database/migrations/2020_10_27_102330_create_tasks_table.php index 075a2e8..bc53843 100644 --- a/database/migrations/2020_10_27_102330_create_tasks_table.php +++ b/database/migrations/2020_10_27_102330_create_tasks_table.php @@ -4,8 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class extends Migration -{ +return new class extends Migration { public function up() { Schema::create('tasks', function (Blueprint $table) { @@ -15,10 +14,11 @@ public function up() $table->text('description'); $table->tinyInteger('flag')->nullable()->index(); - - $table->boolean('completed')->index(); - $table->dateTime('reminder')->nullable(); + $table->smallInteger('status')->nullable(); + $table->dateTime('from')->nullable(); + $table->dateTime('to')->nullable(); + $table->boolean('muted')->default(false); $table->unsignedInteger('allocated_to')->nullable()->index(); $table->foreign('allocated_to')->references('id')->on('users'); diff --git a/database/migrations/2020_10_27_102337_create_structure_for_tasks.php b/database/migrations/2020_10_27_102337_create_structure_for_tasks.php index 9c90464..24d768b 100644 --- a/database/migrations/2020_10_27_102337_create_structure_for_tasks.php +++ b/database/migrations/2020_10_27_102337_create_structure_for_tasks.php @@ -2,8 +2,7 @@ use LaravelEnso\Migrator\Database\Migration; -return new class extends Migration -{ +return new class extends Migration { protected array $permissions = [ ['name' => 'tasks.index', 'description' => 'Show index for tasks', 'is_default' => false], ['name' => 'tasks.create', 'description' => 'Create task', 'is_default' => false], diff --git a/database/migrations/2022_07_01_103245_create_task_checklist_items.php b/database/migrations/2022_07_01_103245_create_task_checklist_items.php new file mode 100644 index 0000000..ba63c82 --- /dev/null +++ b/database/migrations/2022_07_01_103245_create_task_checklist_items.php @@ -0,0 +1,25 @@ +id(); + $table->foreignId('task_id')->constrained('tasks'); + + $table->string('name'); + $table->unsignedInteger('order_index')->nullable(); + $table->boolean('is_completed'); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('task_checklist_items'); + } +}; diff --git a/database/migrations/2022_07_01_103248_create_structure_for_task_checklist_items.php b/database/migrations/2022_07_01_103248_create_structure_for_task_checklist_items.php new file mode 100644 index 0000000..edea620 --- /dev/null +++ b/database/migrations/2022_07_01_103248_create_structure_for_task_checklist_items.php @@ -0,0 +1,14 @@ + 'tasks.checklistItems.store', 'description' => 'Store a new check list', 'is_default' => false], + ['name' => 'tasks.checklistItems.update', 'description' => 'Update check list', 'is_default' => false], + ['name' => 'tasks.checklistItems.destroy', 'description' => 'Delete check list', 'is_default' => false], + ]; + + protected ?string $parentMenu = ''; +}; + diff --git a/database/migrations/2022_07_20_104852_create_task_comments_table.php b/database/migrations/2022_07_20_104852_create_task_comments_table.php new file mode 100644 index 0000000..7a7831c --- /dev/null +++ b/database/migrations/2022_07_20_104852_create_task_comments_table.php @@ -0,0 +1,29 @@ +increments('id'); + $table->foreignId('task_id')->constrained(); + $table->text('body'); + + $table->integer('created_by')->unsigned()->nullable()->index(); + $table->foreign('created_by')->references('id')->on('users'); + + $table->integer('updated_by')->unsigned()->nullable(); + $table->foreign('updated_by')->references('id')->on('users'); + + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('task_comments'); + } +}; diff --git a/database/migrations/2022_07_20_160001_create_structure_for_task_comments.php b/database/migrations/2022_07_20_160001_create_structure_for_task_comments.php new file mode 100644 index 0000000..98e3713 --- /dev/null +++ b/database/migrations/2022_07_20_160001_create_structure_for_task_comments.php @@ -0,0 +1,12 @@ + 'tasks.comments.index', 'description' => 'Show index for comments', 'is_default' => false], + ['name' => 'tasks.comments.store', 'description' => 'Store a new comment', 'is_default' => false], + ['name' => 'tasks.comments.update', 'description' => 'Update comment', 'is_default' => false], + ['name' => 'tasks.comments.destroy', 'description' => 'Delete comment', 'is_default' => false], + ]; +}; diff --git a/routes/api.php b/routes/api.php index 3c6f7c2..8308e51 100644 --- a/routes/api.php +++ b/routes/api.php @@ -33,4 +33,7 @@ Route::get('', Index::class)->name('index'); Route::get('users', Users::class)->name('users'); + + require __DIR__.'/checklistsItems.php'; + require __DIR__.'/comments.php'; }); diff --git a/routes/checklistsItems.php b/routes/checklistsItems.php new file mode 100644 index 0000000..90f8ead --- /dev/null +++ b/routes/checklistsItems.php @@ -0,0 +1,14 @@ +as('checklistItems.') + ->group(function () { + Route::post('', Store::class)->name('store'); + Route::patch('{checklistItem}', Update::class)->name('update'); + Route::delete('{checklistItem}', Destroy::class)->name('destroy'); + }); diff --git a/routes/comments.php b/routes/comments.php new file mode 100644 index 0000000..a43bf3d --- /dev/null +++ b/routes/comments.php @@ -0,0 +1,16 @@ +as('comments.') + ->group(function () { + Route::get('', Index::class)->name('index'); + Route::post('', Store::class)->name('store'); + Route::patch('{comment}', Update::class)->name('update'); + Route::delete('{comment}', Destroy::class)->name('destroy'); + }); diff --git a/src/AppServiceProvider.php b/src/AppServiceProvider.php index 5372ad4..76ab546 100644 --- a/src/AppServiceProvider.php +++ b/src/AppServiceProvider.php @@ -7,7 +7,9 @@ use LaravelEnso\DynamicMethods\Services\Methods; use LaravelEnso\Tasks\Commands\SendTaskReminders; use LaravelEnso\Tasks\DynamicRelations\Tasks; +use LaravelEnso\Tasks\Models\ChecklistItem; use LaravelEnso\Tasks\Models\Task as Model; +use LaravelEnso\Tasks\Observers\ChecklistItem as ChecklistItemObserver; use LaravelEnso\Tasks\Observers\Task as Observer; use LaravelEnso\Users\Models\User; @@ -20,6 +22,7 @@ public function boot() ->command() ->relations() ->observers(); + ChecklistItem::observe(ChecklistItemObserver::class); } private function load(): self diff --git a/src/AuthServiceProvider.php b/src/AuthServiceProvider.php index ec6d91f..b15b6d8 100644 --- a/src/AuthServiceProvider.php +++ b/src/AuthServiceProvider.php @@ -3,13 +3,16 @@ namespace LaravelEnso\Tasks; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; +use LaravelEnso\Tasks\Models\Comment; use LaravelEnso\Tasks\Models\Task; +use LaravelEnso\Tasks\Policies\Comment as TaskCommentPolicy; use LaravelEnso\Tasks\Policies\Task as Policy; class AuthServiceProvider extends ServiceProvider { protected $policies = [ - Task::class => Policy::class, + Task::class => Policy::class, + Comment::class => TaskCommentPolicy::class, ]; public function boot() diff --git a/src/EnumServiceProvider.php b/src/EnumServiceProvider.php index b644633..e79749f 100644 --- a/src/EnumServiceProvider.php +++ b/src/EnumServiceProvider.php @@ -4,10 +4,12 @@ use LaravelEnso\Enums\EnumServiceProvider as ServiceProvider; use LaravelEnso\Tasks\Enums\Flags; +use LaravelEnso\Tasks\Enums\Statuses; class EnumServiceProvider extends ServiceProvider { public $register = [ - 'flags' => Flags::class, + 'flags' => Flags::class, + 'Statuses' => Statuses::class, ]; } diff --git a/src/Enums/Statuses.php b/src/Enums/Statuses.php new file mode 100644 index 0000000..a97fafc --- /dev/null +++ b/src/Enums/Statuses.php @@ -0,0 +1,18 @@ + 'New', + self::InProgress => 'In Progress', + self::Finished => 'Finished', + ]; +} diff --git a/src/Forms/Builders/Task.php b/src/Forms/Builders/Task.php index 3fed158..61f27e7 100644 --- a/src/Forms/Builders/Task.php +++ b/src/Forms/Builders/Task.php @@ -4,6 +4,7 @@ use Illuminate\Support\Facades\Auth; use LaravelEnso\Forms\Services\Form; +use LaravelEnso\Tasks\Enums\Statuses; use LaravelEnso\Tasks\Models\Task as Model; class Task @@ -21,8 +22,9 @@ public function __construct() public function create() { - return $this->form->hide('completed') + return $this->form->hide('status') ->value('allocated_to', Auth::id()) + ->value('status', Statuses::New) ->create(); } diff --git a/src/Forms/Templates/task.json b/src/Forms/Templates/task.json index f0f91a4..7d7f90d 100644 --- a/src/Forms/Templates/task.json +++ b/src/Forms/Templates/task.json @@ -22,11 +22,21 @@ "type": "input", "content": "text" } + }, + { + "label": "Status", + "name": "status", + "value": null, + "meta": { + "type": "select", + "options": "LaravelEnso\\Tasks\\Enums\\Statuses", + "placeholder": "Choose Task Status" + } } ] }, { - "columns": 3, + "columns": 2, "fields": [ { "label": "Allocated To", @@ -48,10 +58,43 @@ "format": "Y-m-d H:i:s", "time": true } + } + ] + }, + { + "columns": 2, + "fields": [ + { + "label": "From", + "name": "from", + "value": "", + "meta": { + "type": "datepicker", + "altFormat": "m-d-Y H:i", + "format": "Y-m-d H:i:s", + "time": true + } }, { - "label": "Completed", - "name": "completed", + "label": "To", + "name": "to", + "value": "", + "meta": { + "type": "datepicker", + "altFormat": "m-d-Y H:i", + "format": "Y-m-d H:i:s", + "time": true + } + } + ] + }, + { + "columns": "custom", + "fields": [ + { + "column": 3, + "label": "Muted", + "name": "muted", "value": false, "meta": { "type": "input", @@ -74,4 +117,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/Http/Controllers/Tasks/ChecklistItems/Destroy.php b/src/Http/Controllers/Tasks/ChecklistItems/Destroy.php new file mode 100644 index 0000000..9e325fd --- /dev/null +++ b/src/Http/Controllers/Tasks/ChecklistItems/Destroy.php @@ -0,0 +1,18 @@ +delete(); + + return [ + 'message' => __('The item was successfully deleted'), + ]; + } +} diff --git a/src/Http/Controllers/Tasks/ChecklistItems/Store.php b/src/Http/Controllers/Tasks/ChecklistItems/Store.php new file mode 100644 index 0000000..2988bfd --- /dev/null +++ b/src/Http/Controllers/Tasks/ChecklistItems/Store.php @@ -0,0 +1,21 @@ +fill($request->validated() + ['is_completed' => false])->save(); + + return [ + 'message' => __('The item was successfully created'), + 'param' => ['checklist' => $checklistItem->id], + 'data' => $checklistItem, + ]; + } +} diff --git a/src/Http/Controllers/Tasks/ChecklistItems/Update.php b/src/Http/Controllers/Tasks/ChecklistItems/Update.php new file mode 100644 index 0000000..9826d08 --- /dev/null +++ b/src/Http/Controllers/Tasks/ChecklistItems/Update.php @@ -0,0 +1,17 @@ +update($request->validated()); + + return ['message' => __('The item was successfully updated')]; + } +} diff --git a/src/Http/Controllers/Tasks/Comments/Destroy.php b/src/Http/Controllers/Tasks/Comments/Destroy.php new file mode 100644 index 0000000..42aee75 --- /dev/null +++ b/src/Http/Controllers/Tasks/Comments/Destroy.php @@ -0,0 +1,21 @@ +authorize('destroy', $comment); + + $comment->delete(); + + return ['count' => $comment->count()]; + } +} diff --git a/src/Http/Controllers/Tasks/Comments/Index.php b/src/Http/Controllers/Tasks/Comments/Index.php new file mode 100644 index 0000000..826d348 --- /dev/null +++ b/src/Http/Controllers/Tasks/Comments/Index.php @@ -0,0 +1,22 @@ +whereTaskId($request->validated()) + ->with('createdBy.person', 'createdBy.avatar', 'updatedBy') + ->get(); + + return Resource::collection($comments)->additional([ + 'humanReadableDates' => Config::get('enso.comments.humanReadableDates'), + ]); + } +} diff --git a/src/Http/Controllers/Tasks/Comments/Store.php b/src/Http/Controllers/Tasks/Comments/Store.php new file mode 100644 index 0000000..8114d2e --- /dev/null +++ b/src/Http/Controllers/Tasks/Comments/Store.php @@ -0,0 +1,21 @@ +fill($request->validatedExcept('path')); + tap($comment)->save(); + + return new Resource($comment->load([ + 'createdBy.person', 'createdBy.avatar', + ])); + } +} diff --git a/src/Http/Controllers/Tasks/Comments/Update.php b/src/Http/Controllers/Tasks/Comments/Update.php new file mode 100644 index 0000000..ae591a8 --- /dev/null +++ b/src/Http/Controllers/Tasks/Comments/Update.php @@ -0,0 +1,24 @@ +authorize('update', $comment); + tap($comment)->update($request->only('body')); + + return new Resource($comment->load([ + 'createdBy.person', 'createdBy.avatar', 'updatedBy', + ])); + } +} diff --git a/src/Http/Controllers/Tasks/Options.php b/src/Http/Controllers/Tasks/Options.php new file mode 100644 index 0000000..3f8c6f4 --- /dev/null +++ b/src/Http/Controllers/Tasks/Options.php @@ -0,0 +1,14 @@ +load( + 'checklistItems', + 'allocatedTo.person', + 'allocatedTo.avatar', + 'createdBy.avatar', + 'createdBy.person' + ); + + return ['task' => new TaskResource($task)]; + } +} diff --git a/src/Http/Requests/Comments/ValidateCommentFetch.php b/src/Http/Requests/Comments/ValidateCommentFetch.php new file mode 100644 index 0000000..e453ba6 --- /dev/null +++ b/src/Http/Requests/Comments/ValidateCommentFetch.php @@ -0,0 +1,20 @@ + 'required', + ]; + } +} diff --git a/src/Http/Requests/Comments/ValidateCommentStore.php b/src/Http/Requests/Comments/ValidateCommentStore.php new file mode 100644 index 0000000..471b846 --- /dev/null +++ b/src/Http/Requests/Comments/ValidateCommentStore.php @@ -0,0 +1,18 @@ + 'required', + 'path' => 'required', + ]; + } +} diff --git a/src/Http/Requests/Comments/ValidateCommentUpdate.php b/src/Http/Requests/Comments/ValidateCommentUpdate.php new file mode 100644 index 0000000..19824ad --- /dev/null +++ b/src/Http/Requests/Comments/ValidateCommentUpdate.php @@ -0,0 +1,21 @@ + 'required', + 'path' => 'required', + ]; + } +} diff --git a/src/Http/Requests/ValidateChecklistItem.php b/src/Http/Requests/ValidateChecklistItem.php new file mode 100644 index 0000000..b26f488 --- /dev/null +++ b/src/Http/Requests/ValidateChecklistItem.php @@ -0,0 +1,30 @@ + "{$this->requiredOrFilled()}|string|max:255", + 'task_id' => "{$this->requiredOrFilled()}|integer|exists:tasks,id", + 'order_index' => 'nullable|integer', + 'is_completed' => 'nullable|boolean', + ]; + } + + private function requiredOrFilled() + { + return $this->method() === 'POST' + ? 'required' + : 'filled'; + } +} diff --git a/src/Http/Requests/ValidateTask.php b/src/Http/Requests/ValidateTask.php index bd9054c..a8f7109 100644 --- a/src/Http/Requests/ValidateTask.php +++ b/src/Http/Requests/ValidateTask.php @@ -5,6 +5,7 @@ use Illuminate\Foundation\Http\FormRequest; use Illuminate\Support\Carbon; use LaravelEnso\Tasks\Enums\Flags; +use LaravelEnso\Tasks\Enums\Statuses; use LaravelEnso\Tasks\Models\Task; class ValidateTask extends FormRequest @@ -17,12 +18,15 @@ public function authorize() public function rules() { return [ - 'name' => "{$this->requiredOrFilled()}|string", - 'description' => 'filled', - 'flag' => 'nullable|in:'.Flags::keys()->implode(','), - 'reminder' => 'nullable|date', - 'allocated_to' => "{$this->requiredOrFilled()}|exists:users,id", - 'completed' => "{$this->requiredOrFilled()}|boolean", + 'name' => "{$this->requiredOrFilled()}|string", + 'description' => 'filled', + 'flag' => 'nullable|in:'.Flags::keys()->implode(','), + 'reminder' => 'nullable|date', + 'allocated_to' => "{$this->requiredOrFilled()}|exists:users,id", + 'status' => "{$this->requiredOrFilled()}|in:".Statuses::keys()->implode(','), + 'from' => "{$this->requiredOrFilled()}|date", + 'to' => "{$this->requiredOrFilled()}|date", + 'muted' => 'nullable|boolean', ]; } diff --git a/src/Http/Resources/ChecklistItem.php b/src/Http/Resources/ChecklistItem.php new file mode 100644 index 0000000..b32a918 --- /dev/null +++ b/src/Http/Resources/ChecklistItem.php @@ -0,0 +1,20 @@ + $this->id, + 'name' => $this->name, + 'task_id' => $this->task_id, + 'is_completed' => $this->is_completed, + 'orderIndex' => $this->order_index, + 'createdAt' => $this->created_at->toDatetimeString(), + ]; + } +} diff --git a/src/Http/Resources/Comment.php b/src/Http/Resources/Comment.php new file mode 100644 index 0000000..23a478c --- /dev/null +++ b/src/Http/Resources/Comment.php @@ -0,0 +1,32 @@ + $this->id, + 'body' => $this->body, + 'owner' => new User($this->whenLoaded('createdBy')), + 'isEditable' => $this->isEditable($request), + 'isDeletable' => $this->isDeletable($request), + 'createdAt' => $this->created_at->toDatetimeString(), + 'updatedAt' => $this->updated_at->toDatetimeString(), + ]; + } + + public function isEditable($request) + { + return $request->user()->can('update', $this->resource); + } + + public function isDeletable($request) + { + return $request->user()->can('destroy', $this->resource); + } +} diff --git a/src/Http/Resources/Task.php b/src/Http/Resources/Task.php index 36e556a..ada02b3 100644 --- a/src/Http/Resources/Task.php +++ b/src/Http/Resources/Task.php @@ -3,18 +3,33 @@ namespace LaravelEnso\Tasks\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; +use Illuminate\Support\Carbon; class Task extends JsonResource { public function toArray($request) { return [ - 'id' => $this->id, - 'name' => $this->name, - 'description' => $this->description, - 'flag' => $this->flag, - 'overdue' => $this->overdue(), - 'reminder' => $this->reminder, + 'id' => $this->id, + 'name' => $this->name, + 'status' => $this->status, + 'description' => $this->description, + 'flag' => $this->flag, + 'overdue' => $this->overdue(), + 'reminder' => $this->reminder, + 'from' => Carbon::parse($this->from)->toFormattedDateString(), + 'to' => Carbon::parse($this->to)->toFormattedDateString(), + 'taskChecklistItems' => ChecklistItem::collection($this->whenLoaded('checklistItems')), + 'completedChecklist' => $this->completedChecklist(), + 'allocatedTo' => $this->allocatedTo, + 'createdBy' => $this->createdBy->person->name, + 'updatedAt' => $this->updated_at->diffForHumans(), + 'muted' => $this->muted, ]; } + + private function completedChecklist(): string + { + return "{$this->checklistItems()->completed()->count()}/{$this->checklistItems->count()}"; + } } diff --git a/src/Models/ChecklistItem.php b/src/Models/ChecklistItem.php new file mode 100644 index 0000000..7de4d05 --- /dev/null +++ b/src/Models/ChecklistItem.php @@ -0,0 +1,30 @@ + 'boolean', + ]; + + public function task(): BelongsTo + { + return $this->belongsTo(Task::class); + } + + public function scopeCompleted($query) + { + return $query->where('is_completed', true); + } +} diff --git a/src/Models/Comment.php b/src/Models/Comment.php new file mode 100644 index 0000000..7f26c02 --- /dev/null +++ b/src/Models/Comment.php @@ -0,0 +1,19 @@ + 'boolean']; + protected $casts = ['muted' => 'boolean']; public function allocatedTo(): Relation { @@ -54,12 +55,32 @@ public function scopeVisible($query) public function scopePending($query) { - return $query->whereCompleted(false); + return $query->whereStatus(Statuses::InProgress); } public function scopeCompleted($query) { - return $query->whereCompleted(true); + return $query->whereStatus(Statuses::Finished); + } + + public function overdue(): bool + { + return $this->status !== Statuses::Finished + && $this->reminder?->lessThan(Carbon::now()); + } + + public function updateStatus(): void + { + $completedItems = $this->checklistItems()->completed()->count(); + $totalItems = $this->checklistItems()->count(); + + $status = match ($completedItems) { + $totalItems => Statuses::Finished, + 0 => Statuses::New, + default => Statuses::InProgress, + }; + + $this->update(['status' => $status]); } public function setReminderAttribute($dateTime) @@ -78,10 +99,4 @@ public function remind() $this->update(['reminded_at' => Carbon::now()]); } - - public function overdue(): bool - { - return !$this->completed - && $this->reminder?->lessThan(Carbon::now()); - } } diff --git a/src/Observers/ChecklistItem.php b/src/Observers/ChecklistItem.php new file mode 100644 index 0000000..d2a44c7 --- /dev/null +++ b/src/Observers/ChecklistItem.php @@ -0,0 +1,25 @@ +task->updateStatus(); + } + + public function updated(CheckListModel $checklist) + { + if ($checklist->isDirty('is_completed')) { + $checklist->task->updateStatus(); + } + } + + public function deleted(CheckListModel $checklist) + { + $checklist->task->updateStatus(); + } +} diff --git a/src/Policies/Comment.php b/src/Policies/Comment.php new file mode 100644 index 0000000..56ebc08 --- /dev/null +++ b/src/Policies/Comment.php @@ -0,0 +1,43 @@ +isAdmin() || $user->isSupervisor()) { + return true; + } + } + + public function update(User $user, Model $comment) + { + return $this->ownsComment($user, $comment) + && $this->isRecent($comment); + } + + public function destroy(User $user, Model $comment) + { + return $this->ownsComment($user, $comment) + && $this->isRecent($comment); + } + + private function ownsComment(User $user, Model $comment) + { + return $user->id === (int) $comment->created_by; + } + + private function isRecent(Model $comment) + { + return $comment->created_at->diffInSeconds(Carbon::now()) + < config('enso.comments.editableTimeLimit'); + } +} diff --git a/src/Tables/Builders/Task.php b/src/Tables/Builders/Task.php index 4c61c90..9c441cd 100644 --- a/src/Tables/Builders/Task.php +++ b/src/Tables/Builders/Task.php @@ -10,6 +10,7 @@ use LaravelEnso\Tables\Contracts\ConditionalActions; use LaravelEnso\Tables\Contracts\CustomFilter; use LaravelEnso\Tables\Contracts\Table; +use LaravelEnso\Tasks\Enums\Statuses; use LaravelEnso\Tasks\Models\Task as Model; class Task implements Table, AuthenticatesOnExport, CustomFilter, ConditionalActions @@ -19,13 +20,14 @@ class Task implements Table, AuthenticatesOnExport, CustomFilter, ConditionalAct public function query(): Builder { $now = Carbon::now(); - $overdue = "completed = true and reminder >= '{$now}'"; + $finished = Statuses::Finished; + $overdue = "status={$finished} and reminder >= '{$now}'"; return Model::visible() ->with('createdBy.avatar', 'createdBy.person') ->with('allocatedTo.avatar', 'allocatedTo.person') ->selectRaw(" - tasks.id, tasks.name, tasks.description, tasks.flag, tasks.completed, + tasks.id, tasks.status, tasks.name, tasks.description, tasks.flag, tasks.allocated_to, tasks.reminder, tasks.reminder as rawReminder, created_by, created_at, {$overdue} as overdue "); diff --git a/src/Tables/Templates/tasks.json b/src/Tables/Templates/tasks.json index a0ee75f..c7ff00e 100644 --- a/src/Tables/Templates/tasks.json +++ b/src/Tables/Templates/tasks.json @@ -5,92 +5,107 @@ "buttons": [ "excel", "create", + "show", "edit", "destroy" ], - "strip": ["allocated_to", "created_by"], - "columns": [{ - "label": "Name", - "name": "name", - "data": "tasks.name", - "meta": [ - "slot", - "searchable" - ] - }, { - "label": "Flag", - "name": "flag", - "data": "tasks.flag", - "meta": [ - "sortable", - "slot" - ], - "enum": "LaravelEnso\\Tasks\\Enums\\Flags" - }, { - "label": "Reminder", - "name": "reminder", - "data": "tasks.reminder", - "dateFormat": "Y-m-d H:i:s", - "meta": [ - "sortable", - "slot", - "datetime" - ] - }, { - "label": "Allocated To", - "name": "allocatedTo", - "data": "tasks.allocatedTo", - "resource": "LaravelEnso\\Users\\Http\\Resources\\User", - "meta": [ - "slot", - "notExportable" - ] - }, { - "label": "Completed", - "name": "completed", - "data": "tasks.completed", - "meta": [ - "sortable", - "slot" - ] - }, { - "label": "Created At", - "name": "created_at", - "data": "tasks.created_at", - "meta": [ - "sortable", - "date" - ] - }, { - "label": "By", - "name": "createdBy", - "data": "tasks.createdBy", - "resource": "LaravelEnso\\Users\\Http\\Resources\\User", - "meta": [ - "slot", - "notExportable" - ] - }, { - "label": "Raw Reminder", - "name": "rawReminder", - "data": "tasks.reminder", - "meta": [ - "rogue", - "notExportable" - ] - }, { - "label": "Allocated", - "name": "allocatedTo.person.name", - "data": "tasks.allocatedTo.person", - "meta": [ - "rogue" - ] - }, { - "label": "Creator", - "name": "createdBy.person.name", - "data": "tasks.createdBy.person", - "meta": [ - "rogue" - ] - }] + "strip": [ + "allocated_to", + "created_by" + ], + "columns": [ + { + "label": "Name", + "name": "name", + "data": "tasks.name", + "meta": [ + "slot", + "searchable" + ] + }, + { + "label": "Status", + "name": "status", + "data": "tasks.status", + "enum": "App\\Enums\\TaskStatuses", + "meta": [ + "slot" + ] + }, + { + "label": "Flag", + "name": "flag", + "data": "tasks.flag", + "meta": [ + "sortable", + "slot" + ], + "enum": "LaravelEnso\\Tasks\\Enums\\Flags" + }, + { + "label": "Reminder", + "name": "reminder", + "data": "tasks.reminder", + "dateFormat": "Y-m-d H:i:s", + "meta": [ + "sortable", + "slot", + "datetime" + ] + }, + { + "label": "Allocated To", + "name": "allocatedTo", + "data": "tasks.allocatedTo", + "resource": "LaravelEnso\\Users\\Http\\Resources\\User", + "meta": [ + "slot", + "notExportable" + ] + }, + { + "label": "Created At", + "name": "created_at", + "data": "tasks.created_at", + "meta": [ + "sortable", + "date" + ] + }, + { + "label": "By", + "name": "createdBy", + "data": "tasks.createdBy", + "resource": "LaravelEnso\\Users\\Http\\Resources\\User", + "meta": [ + "slot", + "notExportable" + ] + }, + { + "label": "Raw Reminder", + "name": "rawReminder", + "data": "tasks.reminder", + "meta": [ + "rogue", + "notExportable" + ] + }, + { + "label": "Allocated", + "name": "allocatedTo.person.name", + "data": "tasks.allocatedTo.person", + "meta": [ + "rogue" + ] + }, + { + "label": "Creator", + "name": "createdBy.person.name", + "data": "tasks.createdBy.person", + "meta": [ + "rogue" + ] + } + ] } diff --git a/src/Upgrades/From.php b/src/Upgrades/From.php new file mode 100644 index 0000000..0a0db39 --- /dev/null +++ b/src/Upgrades/From.php @@ -0,0 +1,22 @@ +dateTime('from')->nullable()->after('reminder'); + }); + } +} diff --git a/src/Upgrades/Muted.php b/src/Upgrades/Muted.php new file mode 100644 index 0000000..44d1d94 --- /dev/null +++ b/src/Upgrades/Muted.php @@ -0,0 +1,22 @@ +boolean('muted')->default(false)->after('reminder'); + }); + } +} diff --git a/src/Upgrades/Permissions.php b/src/Upgrades/Permissions.php new file mode 100644 index 0000000..6149ec6 --- /dev/null +++ b/src/Upgrades/Permissions.php @@ -0,0 +1,16 @@ + 'tasks.show', 'description' => 'Display task information', 'is_default' => true], + ['name' => 'tasks.options', 'description' => 'Get tasks options for select', 'is_default' => false], + ]; +} diff --git a/src/Upgrades/Statuses.php b/src/Upgrades/Statuses.php new file mode 100644 index 0000000..6c1c267 --- /dev/null +++ b/src/Upgrades/Statuses.php @@ -0,0 +1,42 @@ +smallInteger('status')->nullable()->after('reminder'); + }); + } + + public function migrateData(): void + { + Task::whereCompleted(false) + ->update(['status' => StatusesEnum::New]); + Task::whereCompleted(true) + ->update(['status' => StatusesEnum::Finished]); + } + + public function migratePostDataMigration(): void + { + Schema::table('tasks', function ($table) { + $table->smallInteger('status')->nullable('false')->change(); + $table->dropColumn('completed'); + }); + } +} diff --git a/src/Upgrades/To.php b/src/Upgrades/To.php new file mode 100644 index 0000000..08a228b --- /dev/null +++ b/src/Upgrades/To.php @@ -0,0 +1,22 @@ +dateTime('to')->nullable()->after('reminder'); + }); + } +}