mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 08:49:13 +00:00
feat(filters): list actions count (#372)
This commit is contained in:
parent
4f3091a4a7
commit
2b3fab28c1
4 changed files with 87 additions and 78 deletions
|
@ -27,18 +27,22 @@ func NewFilterRepo(log logger.Logger, db *DB) domain.FilterRepo {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FilterRepo) ListFilters(ctx context.Context) ([]domain.Filter, error) {
|
func (r *FilterRepo) ListFilters(ctx context.Context) ([]domain.Filter, error) {
|
||||||
|
actionCountQuery := r.db.squirrel.
|
||||||
|
Select("COUNT(*)").
|
||||||
|
From("action a").
|
||||||
|
Where("a.filter_id = f.id")
|
||||||
|
|
||||||
queryBuilder := r.db.squirrel.
|
queryBuilder := r.db.squirrel.
|
||||||
Select(
|
Select(
|
||||||
"id",
|
"f.id",
|
||||||
"enabled",
|
"f.enabled",
|
||||||
"name",
|
"f.name",
|
||||||
"match_releases",
|
"f.created_at",
|
||||||
"except_releases",
|
"f.updated_at",
|
||||||
"created_at",
|
|
||||||
"updated_at",
|
|
||||||
).
|
).
|
||||||
From("filter").
|
Column(sq.Alias(actionCountQuery, "action_count")).
|
||||||
OrderBy("name ASC")
|
From("filter f").
|
||||||
|
OrderBy("f.name ASC")
|
||||||
|
|
||||||
query, args, err := queryBuilder.ToSql()
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -56,15 +60,10 @@ func (r *FilterRepo) ListFilters(ctx context.Context) ([]domain.Filter, error) {
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var f domain.Filter
|
var f domain.Filter
|
||||||
|
|
||||||
var matchReleases, exceptReleases sql.NullString
|
if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &f.CreatedAt, &f.UpdatedAt, &f.ActionsCount); err != nil {
|
||||||
|
|
||||||
if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &matchReleases, &exceptReleases, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "error scanning row")
|
return nil, errors.Wrap(err, "error scanning row")
|
||||||
}
|
}
|
||||||
|
|
||||||
f.MatchReleases = matchReleases.String
|
|
||||||
f.ExceptReleases = exceptReleases.String
|
|
||||||
|
|
||||||
filters = append(filters, f)
|
filters = append(filters, f)
|
||||||
}
|
}
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
|
|
|
@ -54,62 +54,63 @@ type Filter struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
MinSize string `json:"min_size"`
|
MinSize string `json:"min_size,omitempty"`
|
||||||
MaxSize string `json:"max_size"`
|
MaxSize string `json:"max_size,omitempty"`
|
||||||
Delay int `json:"delay"`
|
Delay int `json:"delay,omitempty"`
|
||||||
Priority int32 `json:"priority"`
|
Priority int32 `json:"priority,omitempty"`
|
||||||
MaxDownloads int `json:"max_downloads"`
|
MaxDownloads int `json:"max_downloads,omitempty"`
|
||||||
MaxDownloadsUnit FilterMaxDownloadsUnit `json:"max_downloads_unit"`
|
MaxDownloadsUnit FilterMaxDownloadsUnit `json:"max_downloads_unit,omitempty"`
|
||||||
MatchReleases string `json:"match_releases"`
|
MatchReleases string `json:"match_releases,omitempty"`
|
||||||
ExceptReleases string `json:"except_releases"`
|
ExceptReleases string `json:"except_releases,omitempty"`
|
||||||
UseRegex bool `json:"use_regex"`
|
UseRegex bool `json:"use_regex,omitempty"`
|
||||||
MatchReleaseGroups string `json:"match_release_groups"`
|
MatchReleaseGroups string `json:"match_release_groups,omitempty"`
|
||||||
ExceptReleaseGroups string `json:"except_release_groups"`
|
ExceptReleaseGroups string `json:"except_release_groups,omitempty"`
|
||||||
Scene bool `json:"scene"`
|
Scene bool `json:"scene,omitempty"`
|
||||||
Origins []string `json:"origins"`
|
Origins []string `json:"origins,omitempty"`
|
||||||
Bonus []string `json:"bonus"`
|
Bonus []string `json:"bonus,omitempty"`
|
||||||
Freeleech bool `json:"freeleech"`
|
Freeleech bool `json:"freeleech,omitempty"`
|
||||||
FreeleechPercent string `json:"freeleech_percent"`
|
FreeleechPercent string `json:"freeleech_percent,omitempty"`
|
||||||
Shows string `json:"shows"`
|
Shows string `json:"shows,omitempty"`
|
||||||
Seasons string `json:"seasons"`
|
Seasons string `json:"seasons,omitempty"`
|
||||||
Episodes string `json:"episodes"`
|
Episodes string `json:"episodes,omitempty"`
|
||||||
Resolutions []string `json:"resolutions"` // SD, 480i, 480p, 576p, 720p, 810p, 1080i, 1080p.
|
Resolutions []string `json:"resolutions,omitempty"` // SD, 480i, 480p, 576p, 720p, 810p, 1080i, 1080p.
|
||||||
Codecs []string `json:"codecs"` // XviD, DivX, x264, h.264 (or h264), mpeg2 (or mpeg-2), VC-1 (or VC1), WMV, Remux, h.264 Remux (or h264 Remux), VC-1 Remux (or VC1 Remux).
|
Codecs []string `json:"codecs,omitempty"` // XviD, DivX, x264, h.264 (or h264), mpeg2 (or mpeg-2), VC-1 (or VC1), WMV, Remux, h.264 Remux (or h264 Remux), VC-1 Remux (or VC1 Remux).
|
||||||
Sources []string `json:"sources"` // DSR, PDTV, HDTV, HR.PDTV, HR.HDTV, DVDRip, DVDScr, BDr, BD5, BD9, BDRip, BRRip, DVDR, MDVDR, HDDVD, HDDVDRip, BluRay, WEB-DL, TVRip, CAM, R5, TELESYNC, TS, TELECINE, TC. TELESYNC and TS are synonyms (you don't need both). Same for TELECINE and TC
|
Sources []string `json:"sources,omitempty"` // DSR, PDTV, HDTV, HR.PDTV, HR.HDTV, DVDRip, DVDScr, BDr, BD5, BD9, BDRip, BRRip, DVDR, MDVDR, HDDVD, HDDVDRip, BluRay, WEB-DL, TVRip, CAM, R5, TELESYNC, TS, TELECINE, TC. TELESYNC and TS are synonyms (you don't need both). Same for TELECINE and TC
|
||||||
Containers []string `json:"containers"`
|
Containers []string `json:"containers,omitempty"`
|
||||||
MatchHDR []string `json:"match_hdr"`
|
MatchHDR []string `json:"match_hdr,omitempty"`
|
||||||
ExceptHDR []string `json:"except_hdr"`
|
ExceptHDR []string `json:"except_hdr,omitempty"`
|
||||||
MatchOther []string `json:"match_other"`
|
MatchOther []string `json:"match_other,omitempty"`
|
||||||
ExceptOther []string `json:"except_other"`
|
ExceptOther []string `json:"except_other,omitempty"`
|
||||||
Years string `json:"years"`
|
Years string `json:"years,omitempty"`
|
||||||
Artists string `json:"artists"`
|
Artists string `json:"artists,omitempty"`
|
||||||
Albums string `json:"albums"`
|
Albums string `json:"albums,omitempty"`
|
||||||
MatchReleaseTypes []string `json:"match_release_types"` // Album,Single,EP
|
MatchReleaseTypes []string `json:"match_release_types,omitempty"` // Album,Single,EP
|
||||||
ExceptReleaseTypes string `json:"except_release_types"`
|
ExceptReleaseTypes string `json:"except_release_types,omitempty"`
|
||||||
Formats []string `json:"formats"` // MP3, FLAC, Ogg, AAC, AC3, DTS
|
Formats []string `json:"formats,omitempty"` // MP3, FLAC, Ogg, AAC, AC3, DTS
|
||||||
Quality []string `json:"quality"` // 192, 320, APS (VBR), V2 (VBR), V1 (VBR), APX (VBR), V0 (VBR), q8.x (VBR), Lossless, 24bit Lossless, Other
|
Quality []string `json:"quality,omitempty"` // 192, 320, APS (VBR), V2 (VBR), V1 (VBR), APX (VBR), V0 (VBR), q8.x (VBR), Lossless, 24bit Lossless, Other
|
||||||
Media []string `json:"media"` // CD, DVD, Vinyl, Soundboard, SACD, DAT, Cassette, WEB, Other
|
Media []string `json:"media,omitempty"` // CD, DVD, Vinyl, Soundboard, SACD, DAT, Cassette, WEB, Other
|
||||||
PerfectFlac bool `json:"perfect_flac"`
|
PerfectFlac bool `json:"perfect_flac,omitempty"`
|
||||||
Cue bool `json:"cue"`
|
Cue bool `json:"cue,omitempty"`
|
||||||
Log bool `json:"log"`
|
Log bool `json:"log,omitempty"`
|
||||||
LogScore int `json:"log_score"`
|
LogScore int `json:"log_score,omitempty"`
|
||||||
MatchCategories string `json:"match_categories"`
|
MatchCategories string `json:"match_categories,omitempty"`
|
||||||
ExceptCategories string `json:"except_categories"`
|
ExceptCategories string `json:"except_categories,omitempty"`
|
||||||
MatchUploaders string `json:"match_uploaders"`
|
MatchUploaders string `json:"match_uploaders,omitempty"`
|
||||||
ExceptUploaders string `json:"except_uploaders"`
|
ExceptUploaders string `json:"except_uploaders,omitempty"`
|
||||||
Tags string `json:"tags"`
|
Tags string `json:"tags,omitempty"`
|
||||||
ExceptTags string `json:"except_tags"`
|
ExceptTags string `json:"except_tags,omitempty"`
|
||||||
TagsAny string `json:"tags_any"`
|
TagsAny string `json:"tags_any,omitempty"`
|
||||||
ExceptTagsAny string `json:"except_tags_any"`
|
ExceptTagsAny string `json:"except_tags_any,omitempty"`
|
||||||
ExternalScriptEnabled bool `json:"external_script_enabled"`
|
ExternalScriptEnabled bool `json:"external_script_enabled,omitempty"`
|
||||||
ExternalScriptCmd string `json:"external_script_cmd"`
|
ExternalScriptCmd string `json:"external_script_cmd,omitempty"`
|
||||||
ExternalScriptArgs string `json:"external_script_args"`
|
ExternalScriptArgs string `json:"external_script_args,omitempty"`
|
||||||
ExternalScriptExpectStatus int `json:"external_script_expect_status"`
|
ExternalScriptExpectStatus int `json:"external_script_expect_status,omitempty"`
|
||||||
ExternalWebhookEnabled bool `json:"external_webhook_enabled"`
|
ExternalWebhookEnabled bool `json:"external_webhook_enabled,omitempty"`
|
||||||
ExternalWebhookHost string `json:"external_webhook_host"`
|
ExternalWebhookHost string `json:"external_webhook_host,omitempty"`
|
||||||
ExternalWebhookData string `json:"external_webhook_data"`
|
ExternalWebhookData string `json:"external_webhook_data,omitempty"`
|
||||||
ExternalWebhookExpectStatus int `json:"external_webhook_expect_status"`
|
ExternalWebhookExpectStatus int `json:"external_webhook_expect_status,omitempty"`
|
||||||
Actions []*Action `json:"actions"`
|
ActionsCount int `json:"actions_count"`
|
||||||
|
Actions []*Action `json:"actions,omitempty"`
|
||||||
Indexers []Indexer `json:"indexers"`
|
Indexers []Indexer `json:"indexers"`
|
||||||
Downloads *FilterDownloads `json:"-"`
|
Downloads *FilterDownloads `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,16 +76,16 @@ function FilterList({ filters }: FilterListProps) {
|
||||||
<table className="min-w-full">
|
<table className="min-w-full">
|
||||||
<thead className="bg-gray-50 dark:bg-gray-800 text-gray-500 dark:text-gray-400 border-b border-gray-200 dark:border-gray-700">
|
<thead className="bg-gray-50 dark:bg-gray-800 text-gray-500 dark:text-gray-400 border-b border-gray-200 dark:border-gray-700">
|
||||||
<tr>
|
<tr>
|
||||||
{["Enabled", "Name", "Indexers"].map((label) => (
|
{["Enabled", "Name", "Actions", "Indexers"].map((label) => (
|
||||||
<th
|
<th
|
||||||
key={`th-${label}`}
|
key={`th-${label}`}
|
||||||
scope="col"
|
scope="col"
|
||||||
className="px-6 pt-4 pb-3 text-left text-xs font-medium uppercase tracking-wider"
|
className="px-4 pt-4 pb-3 text-left text-xs font-medium uppercase tracking-wider"
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</th>
|
</th>
|
||||||
))}
|
))}
|
||||||
<th scope="col" className="relative px-6 py-3">
|
<th scope="col" className="relative px-4 py-3">
|
||||||
<span className="sr-only">Edit</span>
|
<span className="sr-only">Edit</span>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -297,7 +297,7 @@ function FilterListItem({ filter, idx }: FilterListItemProps) {
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<td
|
<td
|
||||||
className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-100"
|
className="px-4 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-100"
|
||||||
>
|
>
|
||||||
<Switch
|
<Switch
|
||||||
checked={enabled}
|
checked={enabled}
|
||||||
|
@ -317,7 +317,7 @@ function FilterListItem({ filter, idx }: FilterListItemProps) {
|
||||||
/>
|
/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 w-full whitespace-nowrap text-sm font-medium text-gray-900 dark:text-gray-100">
|
<td className="px-4 w-full whitespace-nowrap text-sm font-medium text-gray-900 dark:text-gray-100">
|
||||||
<Link
|
<Link
|
||||||
to={filter.id.toString()}
|
to={filter.id.toString()}
|
||||||
className="hover:text-black dark:hover:text-gray-300 w-full py-4 flex"
|
className="hover:text-black dark:hover:text-gray-300 w-full py-4 flex"
|
||||||
|
@ -325,7 +325,15 @@ function FilterListItem({ filter, idx }: FilterListItemProps) {
|
||||||
{filter.name}
|
{filter.name}
|
||||||
</Link>
|
</Link>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
<td className="px-4 w-full whitespace-nowrap text-sm font-medium text-gray-900 dark:text-gray-100">
|
||||||
|
<Link
|
||||||
|
to={`${filter.id.toString()}/actions`}
|
||||||
|
className="hover:text-black dark:hover:text-gray-300 w-full py-4 flex"
|
||||||
|
>
|
||||||
|
<span className={classNames(filter.actions_count == 0 ? "text-red-500" : "")}>{filter.actions_count}</span>
|
||||||
|
</Link>
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
||||||
{filter.indexers && filter.indexers.map((t) => (
|
{filter.indexers && filter.indexers.map((t) => (
|
||||||
<span
|
<span
|
||||||
key={t.id}
|
key={t.id}
|
||||||
|
@ -335,7 +343,7 @@ function FilterListItem({ filter, idx }: FilterListItemProps) {
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
<td className="px-4 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||||
<FilterItemDropdown
|
<FilterItemDropdown
|
||||||
filter={filter}
|
filter={filter}
|
||||||
onToggle={toggleActive}
|
onToggle={toggleActive}
|
||||||
|
|
1
web/src/types/Filter.d.ts
vendored
1
web/src/types/Filter.d.ts
vendored
|
@ -50,6 +50,7 @@ interface Filter {
|
||||||
except_tags: string;
|
except_tags: string;
|
||||||
tags_any: string;
|
tags_any: string;
|
||||||
except_tags_any: string;
|
except_tags_any: string;
|
||||||
|
actions_count: number;
|
||||||
actions: Action[];
|
actions: Action[];
|
||||||
indexers: Indexer[];
|
indexers: Indexer[];
|
||||||
external_script_enabled: boolean;
|
external_script_enabled: boolean;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue