Add: Edit subactivity
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
4cb2dddb43
commit
9598a44e13
|
@ -32,6 +32,7 @@ class ActivityStoreAction
|
||||||
'name' => 'required|max:255',
|
'name' => 'required|max:255',
|
||||||
'is_filterable' => 'present|boolean',
|
'is_filterable' => 'present|boolean',
|
||||||
'subactivities' => 'present|array',
|
'subactivities' => 'present|array',
|
||||||
|
'subactivities.*' => 'integer',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ class ActivityUpdateAction
|
||||||
'name' => 'required|max:255',
|
'name' => 'required|max:255',
|
||||||
'is_filterable' => 'present|boolean',
|
'is_filterable' => 'present|boolean',
|
||||||
'subactivities' => 'present|array',
|
'subactivities' => 'present|array',
|
||||||
|
'subactivities.*' => 'integer',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Activity\Api;
|
||||||
|
|
||||||
|
use App\Resources\SubactivityResource;
|
||||||
|
use App\Subactivity;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
|
class SubactivityShowAction
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asController(Subactivity $subactivity): JsonResponse
|
||||||
|
{
|
||||||
|
return response()->json([
|
||||||
|
'data' => new SubactivityResource($subactivity),
|
||||||
|
'meta' => SubactivityResource::meta(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ class SubactivityStoreAction
|
||||||
return [
|
return [
|
||||||
'name' => 'required|unique:subactivities,name',
|
'name' => 'required|unique:subactivities,name',
|
||||||
'activities' => 'present|array|min:1',
|
'activities' => 'present|array|min:1',
|
||||||
|
'activities.*' => 'integer',
|
||||||
'is_filterable' => 'present|boolean',
|
'is_filterable' => 'present|boolean',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ class SubactivityUpdateAction
|
||||||
return [
|
return [
|
||||||
'name' => ['required', 'string', 'max:255', Rule::unique('subactivities', 'name')->ignore(request()->route('subactivity')->id)],
|
'name' => ['required', 'string', 'max:255', Rule::unique('subactivities', 'name')->ignore(request()->route('subactivity')->id)],
|
||||||
'activities' => ['present', 'array', 'min:1'],
|
'activities' => ['present', 'array', 'min:1'],
|
||||||
|
'activities.*' => 'integer',
|
||||||
'is_filterable' => 'present|boolean',
|
'is_filterable' => 'present|boolean',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Activity\Resources;
|
||||||
use App\Activity;
|
use App\Activity;
|
||||||
use App\Http\Views\ActivityFilterScope;
|
use App\Http\Views\ActivityFilterScope;
|
||||||
use App\Lib\HasMeta;
|
use App\Lib\HasMeta;
|
||||||
|
use App\Resources\SubactivityResource;
|
||||||
use App\Subactivity;
|
use App\Subactivity;
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
@ -49,7 +50,7 @@ class ActivityResource extends JsonResource
|
||||||
public static function meta(): array
|
public static function meta(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'subactivities' => Subactivity::select('name', 'id', 'is_filterable')->get(),
|
'subactivities' => SubactivityResource::collectionWithoutMeta(Subactivity::get()),
|
||||||
'filter' => ActivityFilterScope::fromRequest(request()->input('filter')),
|
'filter' => ActivityFilterScope::fromRequest(request()->input('filter')),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,13 @@ trait HasMeta
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function collectionWithoutMeta($resource)
|
||||||
|
{
|
||||||
|
return parent::collection($resource);
|
||||||
|
}
|
||||||
|
|
||||||
public static function meta(): array
|
public static function meta(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Resources;
|
||||||
|
|
||||||
|
use App\Activity;
|
||||||
|
use App\Activity\Resources\ActivityResource;
|
||||||
|
use App\Lib\HasMeta;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin Subactivity
|
||||||
|
*/
|
||||||
|
class SubactivityResource extends JsonResource
|
||||||
|
{
|
||||||
|
use HasMeta;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
*
|
||||||
|
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||||
|
*/
|
||||||
|
public function toArray($request)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'name' => $this->name,
|
||||||
|
'is_filterable' => $this->is_filterable,
|
||||||
|
'activities' => $this->activities->pluck('id')->toArray(),
|
||||||
|
'links' => [
|
||||||
|
'show' => route('api.subactivity.show', ['subactivity' => $this->getModel()]),
|
||||||
|
'update' => route('api.subactivity.update', ['subactivity' => $this->getModel()]),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function meta(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'activities' => ActivityResource::collectionWithoutMeta(Activity::get()),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex space-x-3">
|
<div class="flex space-x-3" v-if="model">
|
||||||
<f-text size="sm" id="name" v-model="model.name" label="Name" required></f-text>
|
<f-text size="sm" id="name" v-model="model.name" label="Name" required></f-text>
|
||||||
<f-switch size="sm" v-model="model.is_filterable" name="subactivity_is_filterable" id="subactivity_is_filterable" label="Filterbar"></f-switch>
|
<f-switch size="sm" v-model="model.is_filterable" name="subactivity_is_filterable" id="subactivity_is_filterable" label="Filterbar"></f-switch>
|
||||||
</div>
|
</div>
|
||||||
|
@ -25,12 +25,26 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
async store() {
|
async store() {
|
||||||
try {
|
try {
|
||||||
var response = await this.axios.post('/subactivity', this.model);
|
if (this.model.id) {
|
||||||
this.$emit('stored', response.data);
|
var response = await this.axios.patch(this.model.links.update, this.model);
|
||||||
|
this.$emit('updated', response.data);
|
||||||
|
} else {
|
||||||
|
var response = await this.axios.post('/subactivity', this.model);
|
||||||
|
this.$emit('stored', response.data);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.errorsFromException(e);
|
this.errorsFromException(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async created() {
|
||||||
|
if (this.value.id) {
|
||||||
|
var payload = (await this.axios.get(this.value.links.show)).data;
|
||||||
|
this.model = payload.data;
|
||||||
|
} else {
|
||||||
|
this.model = this.value;
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<form id="actionform" class="grow p-3" @submit.prevent="submit">
|
<form id="actionform" class="grow p-3" @submit.prevent="submit">
|
||||||
<popup heading="Neue Untertätigkeit" v-if="mode === 'edit' && addingSubactivity === true" @close="addingSubactivity = false">
|
<popup heading="Neue Untertätigkeit" v-if="mode === 'edit' && currentSubactivity !== null" @close="currentSubactivity = null">
|
||||||
<subactivity-form class="mt-4" :value="inner.subactivity_model" @stored="reloadSubactivities"></subactivity-form>
|
<subactivity-form class="mt-4" v-if="currentSubactivity" :value="currentSubactivity" @stored="reloadSubactivities" @updated="mergeSubactivity"></subactivity-form>
|
||||||
</popup>
|
</popup>
|
||||||
<div class="flex space-x-3">
|
<div class="flex space-x-3">
|
||||||
<f-text id="name" v-model="inner.name" label="Name" required></f-text>
|
<f-text id="name" v-model="inner.name" label="Name" required></f-text>
|
||||||
|
@ -9,20 +9,15 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="flex space-x-3 items-center mt-6 mb-2">
|
<div class="flex space-x-3 items-center mt-6 mb-2">
|
||||||
<checkboxes-label>Untertätigkeiten</checkboxes-label>
|
<checkboxes-label>Untertätigkeiten</checkboxes-label>
|
||||||
<icon-button icon="plus" v-if="mode === 'edit'" @click.prevent="addingSubactivity = true">Neu</icon-button>
|
<icon-button icon="plus" v-if="mode === 'edit'" @click.prevent="currentSubactivity = inner.subactivity_model">Neu</icon-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid gap-2 sm:grid-cols-2 md:grid-cols-4">
|
<div class="grid gap-2 sm:grid-cols-2 md:grid-cols-4">
|
||||||
<f-switch
|
<div v-for="option in subactivities" class="flex items-center space-x-2">
|
||||||
inline
|
<a href="#" @click.prevent="currentSubactivity = option" class="transition hover:bg-yellow-600 group w-5 h-5 rounded-full flex items-center justify-center flex-none">
|
||||||
size="sm"
|
<svg-sprite src="pencil" class="text-yellow-800 w-3 h-3 group-hover:text-yellow-200 transition"></svg-sprite>
|
||||||
:key="option.id"
|
</a>
|
||||||
v-model="inner.subactivities"
|
<f-switch inline size="sm" :key="option.id" v-model="inner.subactivities" name="subactivities[]" :id="`subactivities-${option.id}`" :value="option.id" :label="option.name"></f-switch>
|
||||||
name="subactivities[]"
|
</div>
|
||||||
:id="`subactivities-${option.id}`"
|
|
||||||
:value="option.id"
|
|
||||||
:label="option.name"
|
|
||||||
v-for="option in subactivities"
|
|
||||||
></f-switch>
|
|
||||||
</div>
|
</div>
|
||||||
<save-button form="actionform"></save-button>
|
<save-button form="actionform"></save-button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -32,7 +27,7 @@
|
||||||
export default {
|
export default {
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
addingSubactivity: false,
|
currentSubactivity: null,
|
||||||
subactivities: [...this.meta.subactivities],
|
subactivities: [...this.meta.subactivities],
|
||||||
inner: {...this.data},
|
inner: {...this.data},
|
||||||
mode: this.data.name === '' ? 'create' : 'edit',
|
mode: this.data.name === '' ? 'create' : 'edit',
|
||||||
|
@ -63,7 +58,20 @@ export default {
|
||||||
_self.subactivities = page.props.meta.subactivities;
|
_self.subactivities = page.props.meta.subactivities;
|
||||||
_self.inner.subactivities.push(model.id);
|
_self.inner.subactivities.push(model.id);
|
||||||
_self.$success('Untertätigkeit gespeichert.');
|
_self.$success('Untertätigkeit gespeichert.');
|
||||||
_self.addingSubactivity = false;
|
_self.currentSubactivity = null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
mergeSubactivity(model) {
|
||||||
|
var _self = this;
|
||||||
|
|
||||||
|
this.$inertia.reload({
|
||||||
|
onSuccess(page) {
|
||||||
|
_self.subactivities = page.props.meta.subactivities;
|
||||||
|
_self.inner.subactivities = _self.inner.subactivities.map((s) => (s.id === model.id ? model : s));
|
||||||
|
_self.$success('Untertätigkeit aktualisiert.');
|
||||||
|
_self.currentSubactivity = null;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,6 +6,7 @@ use App\Activity\Actions\CreateAction as ActivityCreateAction;
|
||||||
use App\Activity\Actions\DestroyAction as ActivityDestroyAction;
|
use App\Activity\Actions\DestroyAction as ActivityDestroyAction;
|
||||||
use App\Activity\Actions\EditAction as ActivityEditAction;
|
use App\Activity\Actions\EditAction as ActivityEditAction;
|
||||||
use App\Activity\Actions\IndexAction as ActivityIndexAction;
|
use App\Activity\Actions\IndexAction as ActivityIndexAction;
|
||||||
|
use App\Activity\Api\SubactivityShowAction;
|
||||||
use App\Activity\Api\SubactivityStoreAction;
|
use App\Activity\Api\SubactivityStoreAction;
|
||||||
use App\Activity\Api\SubactivityUpdateAction;
|
use App\Activity\Api\SubactivityUpdateAction;
|
||||||
use App\Contribution\Actions\FormAction as ContributionFormAction;
|
use App\Contribution\Actions\FormAction as ContributionFormAction;
|
||||||
|
@ -64,4 +65,5 @@ Route::group(['middleware' => 'auth:web'], function (): void {
|
||||||
Route::delete('/activity/{activity}', ActivityDestroyAction::class)->name('activity.destroy');
|
Route::delete('/activity/{activity}', ActivityDestroyAction::class)->name('activity.destroy');
|
||||||
Route::post('/subactivity', SubactivityStoreAction::class)->name('api.subactivity.store');
|
Route::post('/subactivity', SubactivityStoreAction::class)->name('api.subactivity.store');
|
||||||
Route::patch('/subactivity/{subactivity}', SubactivityUpdateAction::class)->name('api.subactivity.update');
|
Route::patch('/subactivity/{subactivity}', SubactivityUpdateAction::class)->name('api.subactivity.update');
|
||||||
|
Route::get('/subactivity/{subactivity}', SubactivityShowAction::class)->name('api.subactivity.show');
|
||||||
});
|
});
|
||||||
|
|
|
@ -34,5 +34,14 @@ class EditTest extends TestCase
|
||||||
'name' => 'Pupu',
|
'name' => 'Pupu',
|
||||||
'is_filterable' => true,
|
'is_filterable' => true,
|
||||||
], $response, 'meta.subactivities.0');
|
], $response, 'meta.subactivities.0');
|
||||||
|
$this->assertInertiaHas([
|
||||||
|
'id' => $activity->subactivities->first()->id,
|
||||||
|
'name' => 'Pupu',
|
||||||
|
'is_filterable' => true,
|
||||||
|
'links' => [
|
||||||
|
'show' => route('api.subactivity.show', ['subactivity' => $activity->subactivities->first()->id]),
|
||||||
|
'update' => route('api.subactivity.update', ['subactivity' => $activity->subactivities->first()->id]),
|
||||||
|
],
|
||||||
|
], $response, 'meta.subactivities.0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature\Activity;
|
||||||
|
|
||||||
|
use App\Activity;
|
||||||
|
use App\Subactivity;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class SubactivityShowTest extends TestCase
|
||||||
|
{
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function testItShowsASubactivity(): void
|
||||||
|
{
|
||||||
|
$this->login()->loginNami()->withoutExceptionHandling();
|
||||||
|
$subactivity = Subactivity::factory()->name('Asas')->filterable()->hasAttached(Activity::factory())->create();
|
||||||
|
|
||||||
|
$response = $this->getJson(route('api.subactivity.show', ['subactivity' => $subactivity]));
|
||||||
|
|
||||||
|
$response->assertJsonPath('data.id', $subactivity->id);
|
||||||
|
$response->assertJsonPath('data.name', $subactivity->name);
|
||||||
|
$response->assertJsonPath('data.links.update', route('api.subactivity.update', ['subactivity' => $subactivity]));
|
||||||
|
$response->assertJsonPath('data.links.show', route('api.subactivity.show', ['subactivity' => $subactivity]));
|
||||||
|
$response->assertJsonPath('data.activities.0', $subactivity->activities->first()->id);
|
||||||
|
$response->assertJsonPath('meta.activities.0.name', $subactivity->activities->first()->name);
|
||||||
|
$response->assertJsonPath('meta.activities.0.id', $subactivity->activities->first()->id);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue