Merge pull request #1572 from linuxserver/feature/default-tag-group

Add a configurable default tag for the dashboard
This commit is contained in:
KodeStar
2026-07-08 18:29:43 +01:00
committed by GitHub
8 changed files with 129 additions and 1 deletions
+12
View File
@@ -123,6 +123,12 @@ class Setting extends Model
$options = (array) json_decode($this->options);
if ($this->key === 'search_provider') {
$options = Search::providers()->pluck('name', 'id')->toArray();
} elseif ($this->key === 'default_tag') {
$options = [];
$tags = Item::where('type', 1)->where('id', '>', 0)->pinned()->orderBy('title', 'asc')->get();
foreach ($tags as $tag) {
$options[$tag->tag_url] = $tag->title;
}
}
$value = (array_key_exists($this->value, $options))
? __($options[$this->value])
@@ -190,6 +196,12 @@ class Setting extends Model
$options = json_decode($this->options);
if ($this->key === 'search_provider') {
$options = Search::providers()->pluck('name', 'id');
} elseif ($this->key === 'default_tag') {
$options = ['' => 'app.options.none'];
$tags = Item::where('type', 1)->where('id', '>', 0)->pinned()->orderBy('title', 'asc')->get();
foreach ($tags as $tag) {
$options[$tag->tag_url] = $tag->title;
}
}
$value = '<select name="value" class="form-control">';
foreach ($options as $key => $opt) {
+15
View File
@@ -349,5 +349,20 @@ class SettingsSeeder extends Seeder
$setting->label = 'app.settings.treat_tags_as';
$setting->save();
}
if (! $setting = Setting::find(15)) {
$setting = new Setting;
$setting->id = 15;
$setting->group_id = 4;
$setting->key = 'default_tag';
$setting->type = 'select';
$setting->label = 'app.settings.default_tag';
$setting->value = '';
$setting->save();
} else {
$setting->group_id = 4;
$setting->label = 'app.settings.default_tag';
$setting->save();
}
}
}
+1
View File
@@ -29,6 +29,7 @@ return array (
'settings.custom_css' => 'Custom CSS',
'settings.custom_js' => 'Custom JavaScript',
'settings.treat_tags_as' => 'Treat Tags As:',
'settings.default_tag' => 'Default tag',
'settings.folders' => 'Folders',
'settings.tags' => 'Tags',
'settings.categories' => 'Categories',
+8
View File
@@ -4287,6 +4287,14 @@ $.when($.ready).then(function () {
alert("Something went wrong: ".concat(responseData.responseText.substring(0, 100)));
});
});
// Auto-select the configured default tag on load (tags mode only)
var taglist = document.getElementById("taglist");
if (taglist !== null) {
var defaultTag = taglist.getAttribute("data-default-tag");
if (typeof defaultTag === "string" && defaultTag !== "") {
$("#taglist .tag[data-tag=\"tag-".concat(defaultTag, "\"]")).trigger("click");
}
}
$("#pinlist").on("click", "a", function (e) {
e.preventDefault();
var current = $(this);
+9
View File
@@ -334,6 +334,15 @@ $.when($.ready).then(() => {
);
});
});
// Auto-select the configured default tag on load (tags mode only)
const taglist = document.getElementById("taglist");
if (taglist !== null) {
const defaultTag = taglist.getAttribute("data-default-tag");
if (typeof defaultTag === "string" && defaultTag !== "") {
$(`#taglist .tag[data-tag="tag-${defaultTag}"]`).trigger("click");
}
}
$("#pinlist").on("click", "a", function (e) {
e.preventDefault();
const current = $(this);
+1 -1
View File
@@ -3,7 +3,7 @@ $treat_tags_as = \App\Setting::fetch('treat_tags_as');
?>
@if( $treat_tags_as == 'tags')
@if($taglist->first())
<div id="taglist" class="taglist">
<div id="taglist" class="taglist" data-default-tag="{{ \App\Setting::fetch('default_tag') }}">
<div class="tag white current" data-tag="all">All</div>
@foreach($taglist as $tag)
<div class="tag link{{ title_color($tag->colour) }}" style="background-color: {{ $tag->colour }}" data-tag="tag-{{ $tag->tag_url }}">{{ $tag->title }}</div>
+22
View File
@@ -4,6 +4,7 @@ namespace Tests\Feature;
use App\Item;
use App\ItemTag;
use App\Setting;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
@@ -80,4 +81,25 @@ class DashTest extends TestCase
$response->assertSee('Tag 1');
$response->assertSee('Tag 2');
}
public function test_dash_exposes_the_configured_default_tag(): void
{
$this->seed();
Setting::where('key', 'treat_tags_as')->update(['value' => 'tags']);
Setting::where('key', 'default_tag')->update(['value' => 'home-dashboard']);
Item::factory()->create([
'title' => 'Home',
'url' => 'home-dashboard',
'type' => 1,
'pinned' => 1,
'user_id' => 0,
]);
$response = $this->get('/');
$response->assertStatus(200);
$response->assertSee('data-default-tag="home-dashboard"', false);
}
}
@@ -2,11 +2,16 @@
namespace Tests\Unit\database\seeders;
use App\Item;
use App\Setting;
use Database\Seeders\SettingsSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class SettingsSeederTest extends TestCase
{
use RefreshDatabase;
/**
* All language keys are defined in all languages based on the en language file.
*/
@@ -18,4 +23,60 @@ class SettingsSeederTest extends TestCase
$this->assertTrue(count($languageMap) === count($languageDirectories));
}
public function test_seeds_the_default_tag_setting(): void
{
$this->seed();
$setting = Setting::where('key', 'default_tag')->first();
$this->assertNotNull($setting);
$this->assertSame('select', $setting->type);
$this->assertSame(4, (int) $setting->group_id);
}
public function test_default_tag_edit_value_lists_all_tags_and_a_none_option(): void
{
$this->seed();
Item::factory()->create([
'title' => 'Home',
'url' => 'home-dashboard',
'type' => 1,
'pinned' => 1,
'user_id' => 0,
]);
Item::factory()->create([
'title' => 'Media',
'url' => 'media',
'type' => 1,
'pinned' => 1,
'user_id' => 0,
]);
// An unpinned tag is not rendered in the dashboard taglist, so it must
// not be offered as a default (selecting it would silently do nothing).
Item::factory()->create([
'title' => 'Archive',
'url' => 'archive',
'type' => 1,
'pinned' => 0,
'user_id' => 0,
]);
$setting = Setting::where('key', 'default_tag')->first();
$editValue = $setting->edit_value;
// A "none" option with an empty value, using the shared translation key.
$this->assertStringContainsString('<option value="" ', $editValue);
$this->assertStringContainsString(__('app.options.none'), $editValue);
// One option per pinned tag: the slug as the value, the raw title as the label.
$this->assertStringContainsString('value="home-dashboard"', $editValue);
$this->assertStringContainsString('>Home</option>', $editValue);
$this->assertStringContainsString('value="media"', $editValue);
$this->assertStringContainsString('>Media</option>', $editValue);
// The unpinned tag is excluded.
$this->assertStringNotContainsString('value="archive"', $editValue);
}
}