mirror of https://github.com/MarceauKa/shaark.git
✨ Move tagged posts to another tag ♻️ Refactored managing tags 🔧 Loader vue component
This commit is contained in:
parent
f7b558ed36
commit
4b829dc843
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Manage;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Post;
|
||||
use App\Tag;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TagsController extends Controller
|
||||
{
|
||||
public function all()
|
||||
{
|
||||
$tags = Tag::withCount('posts')
|
||||
->orderByDesc('posts_count')
|
||||
->get();
|
||||
|
||||
return response()->json($tags);
|
||||
}
|
||||
|
||||
public function move(Request $request, string $from, string $to)
|
||||
{
|
||||
$posts = Post::withAnyTags($from)->get();
|
||||
|
||||
$posts->each(function ($item) use ($to) {
|
||||
$item->attachTag($to);
|
||||
});
|
||||
|
||||
return $this->delete($request, $from);
|
||||
}
|
||||
|
||||
public function delete(Request $request, string $tag)
|
||||
{
|
||||
$tag = Tag::findNamedOrCreate($tag);
|
||||
$tag->delete();
|
||||
|
||||
return response()->json();
|
||||
}
|
||||
}
|
|
@ -22,31 +22,6 @@ class ManageController extends Controller
|
|||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
public function tags()
|
||||
{
|
||||
$tags = Tag::withCount('posts')
|
||||
->orderByDesc('posts_count')
|
||||
->get();
|
||||
|
||||
return view('manage.tags')->with([
|
||||
'page_title' => __('Tags'),
|
||||
'tags' => $tags,
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteTag(Request $request, string $tag, string $hash)
|
||||
{
|
||||
if ($hash != csrf_token()) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$tag = Tag::findNamedOrCreate($tag);
|
||||
$tag->delete();
|
||||
|
||||
$this->flash(__('Tag :name has been deleted', ['name' => $tag->name]), 'success');
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function importForm(Request $request)
|
||||
{
|
||||
return view('manage.import')->with([
|
||||
|
@ -138,4 +113,11 @@ class ManageController extends Controller
|
|||
'page_title' => __('Logins'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function tags()
|
||||
{
|
||||
return view('manage.tags')->with([
|
||||
'page_title' => __('Tags'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Tag;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class TagObserver
|
||||
{
|
||||
public function deleted(Tag $tag)
|
||||
{
|
||||
DB::table('taggables')
|
||||
->where('tag_id', $tag->id)
|
||||
->delete();
|
||||
}
|
||||
}
|
|
@ -2,35 +2,21 @@
|
|||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Events\LinkArchiveRequested;
|
||||
use App\Listeners\MakeLinkArchive;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* The event listener mappings for the application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $listen = [
|
||||
LinkArchiveRequested::class => [
|
||||
MakeLinkArchive::class
|
||||
\App\Events\LinkArchiveRequested::class => [
|
||||
\App\Listeners\MakeLinkArchive::class
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* Register any events for your application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
//
|
||||
\App\Tag::observe(\App\Observers\TagObserver::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
# Unreleased
|
||||
|
||||
## Added
|
||||
|
||||
- Move tagged posts to another tag
|
||||
- Loader vue component
|
||||
|
||||
## Changed
|
||||
|
||||
- Refactored managing tags
|
||||
|
||||
## Fixed
|
||||
|
||||
- Missing translations (custom background images)
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"/js/app.js": "/js/app.js?id=c933c95d37104954a50b",
|
||||
"/js/app.js": "/js/app.js?id=cd52e6201c26087f8be3",
|
||||
"/css/app.css": "/css/app.css?id=a737fd0068ee13780419"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<template>
|
||||
<div class="d-flex align-content-center align-items-center" v-if="loading">
|
||||
<div class="spinner-grow mr-2" role="status"></div>
|
||||
<div>{{ __("Loading") }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
loading: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,107 @@
|
|||
<template>
|
||||
<div class="card">
|
||||
<div class="card-header">{{ __('Tags') }}</div>
|
||||
|
||||
<div class="card-body" v-if="!loading">
|
||||
<div class="alert alert-info" v-if="tags.length === 0">
|
||||
{{ __('No tag') }}
|
||||
</div>
|
||||
|
||||
<table class="table table-borderless table-sm" v-else>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-25">{{ __('Name') }}</th>
|
||||
<th class="w-25">{{ __('Posts') }}</th>
|
||||
<th class="w-50">{{ __('Actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="tag in tags">
|
||||
<td class="align-middle">
|
||||
<a :href="tag.url">{{ tag.name }}</a>
|
||||
</td>
|
||||
<td class="align-middle">{{ tag.posts_count }}</td>
|
||||
<td class="d-flex justify-content-between">
|
||||
<select name="tag" id="tag" class="form-control mr-1 w-auto flex-grow-1" @change="move(tag.name, $event.target.value)">
|
||||
<option value="none">-- {{ __('Move') }} --</option>
|
||||
<option v-for="item in tags"
|
||||
:value="item.name"
|
||||
v-text="item.name"
|
||||
v-if="tag.name !== item.name"
|
||||
></option>
|
||||
</select>
|
||||
|
||||
<confirm tag="button" class="btn btn-danger btn-sm"
|
||||
:text="__('Delete')"
|
||||
:text-confirm="__('Confirm')"
|
||||
@confirmed="remove(tag)"
|
||||
></confirm>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-body" v-else>
|
||||
<loader :loading="loading"></loader>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tags: [],
|
||||
loading: true,
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.fetch();
|
||||
},
|
||||
|
||||
methods: {
|
||||
fetch() {
|
||||
this.loading = true;
|
||||
|
||||
axios.get('/api/manage/tags')
|
||||
.then(response => {
|
||||
this.tags = response.data;
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
this.$toasted.error(this.__("Can't fetch tags"));
|
||||
})
|
||||
},
|
||||
|
||||
move(from, to) {
|
||||
if (to === 'none') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (confirm(this.__("All elements tagged :from will be moved to :to. Selected tag will be deleted. Are you sure?", {from, to}))) {
|
||||
this.loading = true;
|
||||
|
||||
axios.post(`/api/manage/tags/${from}/move/${to}`).then(response => {
|
||||
this.$toasted.success(this.__("Elements tagged :from have been moved to :to.", {from: from, to: to}));
|
||||
this.fetch();
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
remove(tag) {
|
||||
this.loading = true;
|
||||
|
||||
axios.delete(`/api/manage/tags/${tag.name}`).then(response => {
|
||||
this.$toasted.success(this.__("Tag :name has been deleted", {name: tag.name}));
|
||||
this.fetch();
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -65,6 +65,7 @@
|
|||
"Logins": "Connexions",
|
||||
"Import": "Importer",
|
||||
"Export": "Exporter",
|
||||
"Actions": "Actions",
|
||||
"More": "Plus",
|
||||
"Update preview": "Actualiser la prévisualisation",
|
||||
"Manage archive": "Gestion de l'archive",
|
||||
|
@ -76,12 +77,14 @@
|
|||
"Save": "Enregistrer",
|
||||
"Save then archive": "Enregistrer puis archiver",
|
||||
"Add": "Ajouter",
|
||||
"Move": "Déplacer",
|
||||
"Show": "Afficher",
|
||||
"Hide": "Cacher",
|
||||
"Copy": "Copier",
|
||||
"Copied": "Copié",
|
||||
"Choose": "Choisir",
|
||||
"Reset": "Réinitialiser",
|
||||
"Loading": "Chargement",
|
||||
|
||||
"Type / to search": "Tapez / pour chercher",
|
||||
|
||||
|
@ -129,6 +132,8 @@
|
|||
"Search or type a tag": "Cherchez ou tapez un tag",
|
||||
"Can't fetch tags": "Impossible de récupérer les tags",
|
||||
"Tag :name has been deleted": "Le tag :name a été supprimé",
|
||||
"All elements tagged :from will be moved to :to. Selected tag will be deleted. Are you sure?": "Tous les éléments taggés :from seront déplacés vers :to. Le tag sera également supprimé. Êtes-vous sûr ?",
|
||||
"Elements tagged :from have been moved to :to.": "Les éléments taggés :from ont été déplacés vers :to.",
|
||||
|
||||
"Rapid share": "Ajout rapide",
|
||||
"Configure your rapid share button and drag it to your bookmarks menu.": "Configurez votre bouton d'ajout rapide et faite le glisser dans votre barre de favoris.",
|
||||
|
|
|
@ -3,38 +3,7 @@
|
|||
@section('content')
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">{{ __('Tags') }}</div>
|
||||
|
||||
<div class="card-body">
|
||||
@if($tags->isEmpty())
|
||||
<div class="alert alert-info">{{ __('No tag') }}</div>
|
||||
@else
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{{ __('Name') }}</td>
|
||||
<td>{{ __('Posts') }}</td>
|
||||
<td class="text-right">#</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($tags as $tag)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ $tag->url }}">{{ $tag->name }}</a>
|
||||
</td>
|
||||
<td>{{ $tag->posts_count }}</td>
|
||||
<td class="text-right">
|
||||
<confirm tag="button" class="btn btn-danger btn-sm" text="{{ __('Delete') }}" text-confirm="{{ __('Confirm') }}" href="{{ route('manage.tags.delete', [$tag->name, csrf_token()]) }}"></confirm>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<manage-tags></manage-tags>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
|
@ -16,3 +16,14 @@ Route::put('story/{id}', 'StoryController@update')->name('story.update');
|
|||
|
||||
Route::post('chest', 'ChestController@store')->name('chest.store');
|
||||
Route::put('chest/{id}', 'ChestController@update')->name('chest.update');
|
||||
|
||||
Route::group([
|
||||
'as' => 'manage.',
|
||||
'prefix' => 'manage',
|
||||
'middleware' => 'auth:api',
|
||||
'namespace' => 'Manage',
|
||||
], function (\Illuminate\Routing\Router $router) {
|
||||
$router->get('tags', 'TagsController@all')->name('all');
|
||||
$router->delete('tags/{tag}', 'TagsController@delete')->name('delete');
|
||||
$router->post('tags/{from}/move/{to}', 'TagsController@move')->name('move');
|
||||
});
|
||||
|
|
|
@ -41,7 +41,6 @@ Route::post('manage/import', 'ManageController@importStore');
|
|||
Route::get('manage/export', 'ManageController@exportForm')->name('manage.export');
|
||||
Route::post('manage/export', 'ManageController@export');
|
||||
Route::get('manage/tags', 'ManageController@tags')->name('manage.tags');
|
||||
Route::get('manage/tags/delete/{tag}/{hash}', 'ManageController@deleteTag')->name('manage.tags.delete');
|
||||
Route::get('manage/logins', 'ManageController@logins')->name('manage.logins');
|
||||
Route::get('manage/settings', 'ManageController@settingsForm')->name('manage.settings');
|
||||
Route::post('manage/settings', 'ManageController@settingsStore');
|
||||
|
|
Loading…
Reference in New Issue