mirror of
https://github.com/gotson/komga.git
synced 2025-12-06 08:32:25 +01:00
feat(webui): add unavailable condition in series and books filters
Closes: #1580
This commit is contained in:
parent
87d73cc207
commit
1b8fa45ef2
5 changed files with 54 additions and 4 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
import {SearchConditionSeries} from '@/types/komga-search'
|
import {SearchConditionSeries} from '@/types/komga-search'
|
||||||
|
import {FiltersActive, NameValue} from '@/types/filter'
|
||||||
|
|
||||||
export function sortOrFilterActive(sortActive: SortActive, sortDefault: SortActive, filters: FiltersActive): boolean {
|
export function sortOrFilterActive(sortActive: SortActive, sortDefault: SortActive, filters: FiltersActive): boolean {
|
||||||
const sortCustom = sortActive.key !== sortDefault.key || sortActive.order !== sortDefault.order
|
const sortCustom = sortActive.key !== sortDefault.key || sortActive.order !== sortDefault.order
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,14 @@ export class SearchConditionTitleSort implements SearchConditionSeries {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SearchConditionDeleted implements SearchConditionBook, SearchConditionSeries {
|
||||||
|
deleted: SearchOperatorBoolean
|
||||||
|
|
||||||
|
constructor(op: SearchOperatorBoolean) {
|
||||||
|
this.deleted = op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface AuthorMatch {
|
export interface AuthorMatch {
|
||||||
name?: string,
|
name?: string,
|
||||||
role?: string
|
role?: string
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,7 @@ import {
|
||||||
SearchConditionAllOfBook,
|
SearchConditionAllOfBook,
|
||||||
SearchConditionAnyOfBook,
|
SearchConditionAnyOfBook,
|
||||||
SearchConditionAuthor,
|
SearchConditionAuthor,
|
||||||
|
SearchConditionDeleted,
|
||||||
SearchConditionLibraryId,
|
SearchConditionLibraryId,
|
||||||
SearchConditionMediaProfile,
|
SearchConditionMediaProfile,
|
||||||
SearchConditionOneShot,
|
SearchConditionOneShot,
|
||||||
|
|
@ -348,6 +349,15 @@ export default Vue.extend({
|
||||||
nValue: new SearchConditionOneShot(new SearchOperatorIsFalse()),
|
nValue: new SearchConditionOneShot(new SearchOperatorIsFalse()),
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
|
deleted: {
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
name: this.$t('common.unavailable').toString(),
|
||||||
|
value: new SearchConditionDeleted(new SearchOperatorIsTrue()),
|
||||||
|
nValue: new SearchConditionDeleted(new SearchOperatorIsFalse()),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
} as FiltersOptions
|
} as FiltersOptions
|
||||||
},
|
},
|
||||||
filterOptionsPanel(): FiltersOptions {
|
filterOptionsPanel(): FiltersOptions {
|
||||||
|
|
@ -436,11 +446,12 @@ export default Vue.extend({
|
||||||
|
|
||||||
// get filter from query params or local storage and validate with available filter values
|
// get filter from query params or local storage and validate with available filter values
|
||||||
let activeFilters: any
|
let activeFilters: any
|
||||||
if (route.query.readStatus || route.query.tag || authorRoles.some(role => role in route.query) || route.query.oneshot) {
|
if (route.query.readStatus || route.query.tag || authorRoles.some(role => role in route.query) || route.query.oneshot || route.query.deleted) {
|
||||||
activeFilters = {
|
activeFilters = {
|
||||||
readStatus: route.query.readStatus || [],
|
readStatus: route.query.readStatus || [],
|
||||||
tag: route.query.tag || [],
|
tag: route.query.tag || [],
|
||||||
oneshot: route.query.oneshot || [],
|
oneshot: route.query.oneshot || [],
|
||||||
|
deleted: route.query.deleted || [],
|
||||||
}
|
}
|
||||||
authorRoles.forEach((role: string) => {
|
authorRoles.forEach((role: string) => {
|
||||||
activeFilters[role] = route.query[role] || []
|
activeFilters[role] = route.query[role] || []
|
||||||
|
|
@ -471,6 +482,7 @@ export default Vue.extend({
|
||||||
readStatus: this.$_.intersectionWith(filters.readStatus, extractFilterOptionsValues(this.filterOptionsList.readStatus.values), objIsEqual) || [],
|
readStatus: this.$_.intersectionWith(filters.readStatus, extractFilterOptionsValues(this.filterOptionsList.readStatus.values), objIsEqual) || [],
|
||||||
tag: this.$_.intersectionWith(filters.tag, extractFilterOptionsValues(this.filterOptions.tag), objIsEqual) || [],
|
tag: this.$_.intersectionWith(filters.tag, extractFilterOptionsValues(this.filterOptions.tag), objIsEqual) || [],
|
||||||
oneshot: this.$_.intersectionWith(filters.oneshot, extractFilterOptionsValues(this.filterOptionsList.oneshot.values), objIsEqual) || [],
|
oneshot: this.$_.intersectionWith(filters.oneshot, extractFilterOptionsValues(this.filterOptionsList.oneshot.values), objIsEqual) || [],
|
||||||
|
deleted: this.$_.intersectionWith(filters.deleted, extractFilterOptionsValues(this.filterOptionsList.deleted.values), objIsEqual) || [],
|
||||||
} as any
|
} as any
|
||||||
authorRoles.forEach((role: string) => {
|
authorRoles.forEach((role: string) => {
|
||||||
validFilter[role] = filters[role] || []
|
validFilter[role] = filters[role] || []
|
||||||
|
|
@ -581,6 +593,7 @@ export default Vue.extend({
|
||||||
if (this.filters.tag && this.filters.tag.length > 0) this.filtersMode?.tag?.allOf ? conditions.push(new SearchConditionAllOfBook(this.filters.tag)) : conditions.push(new SearchConditionAnyOfBook(this.filters.tag))
|
if (this.filters.tag && this.filters.tag.length > 0) this.filtersMode?.tag?.allOf ? conditions.push(new SearchConditionAllOfBook(this.filters.tag)) : conditions.push(new SearchConditionAnyOfBook(this.filters.tag))
|
||||||
if (this.filters.oneshot && this.filters.oneshot.length > 0) conditions.push(...this.filters.oneshot)
|
if (this.filters.oneshot && this.filters.oneshot.length > 0) conditions.push(...this.filters.oneshot)
|
||||||
if (this.filters.mediaProfile && this.filters.mediaProfile.length > 0) this.filtersMode?.mediaProfile?.allOf ? conditions.push(new SearchConditionAllOfBook(this.filters.mediaProfile)) : conditions.push(new SearchConditionAnyOfBook(this.filters.mediaProfile))
|
if (this.filters.mediaProfile && this.filters.mediaProfile.length > 0) this.filtersMode?.mediaProfile?.allOf ? conditions.push(new SearchConditionAllOfBook(this.filters.mediaProfile)) : conditions.push(new SearchConditionAnyOfBook(this.filters.mediaProfile))
|
||||||
|
if (this.filters.deleted && this.filters.deleted.length > 0) conditions.push(...this.filters.deleted)
|
||||||
authorRoles.forEach((role: string) => {
|
authorRoles.forEach((role: string) => {
|
||||||
if (role in this.filters) {
|
if (role in this.filters) {
|
||||||
const authorConditions = this.filters[role].map((name: string) => {
|
const authorConditions = this.filters[role].map((name: string) => {
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,7 @@ import {
|
||||||
SearchConditionAnyOfSeries,
|
SearchConditionAnyOfSeries,
|
||||||
SearchConditionAuthor,
|
SearchConditionAuthor,
|
||||||
SearchConditionComplete,
|
SearchConditionComplete,
|
||||||
|
SearchConditionDeleted,
|
||||||
SearchConditionGenre,
|
SearchConditionGenre,
|
||||||
SearchConditionLanguage,
|
SearchConditionLanguage,
|
||||||
SearchConditionLibraryId,
|
SearchConditionLibraryId,
|
||||||
|
|
@ -414,6 +415,15 @@ export default Vue.extend({
|
||||||
nValue: new SearchConditionOneShot(new SearchOperatorIsFalse()),
|
nValue: new SearchConditionOneShot(new SearchOperatorIsFalse()),
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
|
deleted: {
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
name: this.$t('common.unavailable').toString(),
|
||||||
|
value: new SearchConditionDeleted(new SearchOperatorIsTrue()),
|
||||||
|
nValue: new SearchConditionDeleted(new SearchOperatorIsFalse()),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
} as FiltersOptions
|
} as FiltersOptions
|
||||||
},
|
},
|
||||||
filterOptionsPanel(): FiltersOptions {
|
filterOptionsPanel(): FiltersOptions {
|
||||||
|
|
@ -435,7 +445,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
...this.filterOptions.genre,
|
...this.filterOptions.genre,
|
||||||
],
|
],
|
||||||
anyAllSelector: true
|
anyAllSelector: true,
|
||||||
},
|
},
|
||||||
tag: {
|
tag: {
|
||||||
name: this.$t('filter.tag').toString(),
|
name: this.$t('filter.tag').toString(),
|
||||||
|
|
@ -610,7 +620,7 @@ export default Vue.extend({
|
||||||
|
|
||||||
// get filter from query params or local storage and validate with available filter values
|
// get filter from query params or local storage and validate with available filter values
|
||||||
let activeFilters: any
|
let activeFilters: any
|
||||||
if (route.query.status || route.query.readStatus || route.query.genre || route.query.tag || route.query.language || route.query.ageRating || route.query.publisher || authorRoles.some(role => role in route.query) || route.query.complete || route.query.oneshot || route.query.sharingLabel) {
|
if (route.query.status || route.query.readStatus || route.query.genre || route.query.tag || route.query.language || route.query.ageRating || route.query.publisher || authorRoles.some(role => role in route.query) || route.query.complete || route.query.oneshot || route.query.sharingLabel || route.query.deleted) {
|
||||||
activeFilters = {
|
activeFilters = {
|
||||||
status: route.query.status || [],
|
status: route.query.status || [],
|
||||||
readStatus: route.query.readStatus || [],
|
readStatus: route.query.readStatus || [],
|
||||||
|
|
@ -623,6 +633,7 @@ export default Vue.extend({
|
||||||
complete: route.query.complete || [],
|
complete: route.query.complete || [],
|
||||||
oneshot: route.query.oneshot || [],
|
oneshot: route.query.oneshot || [],
|
||||||
sharingLabel: route.query.sharingLabel || [],
|
sharingLabel: route.query.sharingLabel || [],
|
||||||
|
deleted: route.query.deleted || [],
|
||||||
}
|
}
|
||||||
authorRoles.forEach((role: string) => {
|
authorRoles.forEach((role: string) => {
|
||||||
activeFilters[role] = route.query[role] || []
|
activeFilters[role] = route.query[role] || []
|
||||||
|
|
@ -661,6 +672,7 @@ export default Vue.extend({
|
||||||
complete: this.$_.intersectionWith(filters.complete, extractFilterOptionsValues(this.filterOptionsList.complete.values), objIsEqual) || [],
|
complete: this.$_.intersectionWith(filters.complete, extractFilterOptionsValues(this.filterOptionsList.complete.values), objIsEqual) || [],
|
||||||
oneshot: this.$_.intersectionWith(filters.oneshot, extractFilterOptionsValues(this.filterOptionsList.oneshot.values), objIsEqual) || [],
|
oneshot: this.$_.intersectionWith(filters.oneshot, extractFilterOptionsValues(this.filterOptionsList.oneshot.values), objIsEqual) || [],
|
||||||
sharingLabel: this.$_.intersectionWith(filters.sharingLabel, extractFilterOptionsValues(this.filterOptions.sharingLabel), objIsEqual) || [],
|
sharingLabel: this.$_.intersectionWith(filters.sharingLabel, extractFilterOptionsValues(this.filterOptions.sharingLabel), objIsEqual) || [],
|
||||||
|
deleted: this.$_.intersectionWith(filters.deleted, extractFilterOptionsValues(this.filterOptionsList.deleted.values), objIsEqual) || [],
|
||||||
} as any
|
} as any
|
||||||
authorRoles.forEach((role: string) => {
|
authorRoles.forEach((role: string) => {
|
||||||
validFilter[role] = filters[role] || []
|
validFilter[role] = filters[role] || []
|
||||||
|
|
@ -781,6 +793,7 @@ export default Vue.extend({
|
||||||
if (this.filters.sharingLabel && this.filters.sharingLabel.length > 0) this.filtersMode?.sharingLabel?.allOf ? conditions.push(new SearchConditionAllOfSeries(this.filters.sharingLabel)) : conditions.push(new SearchConditionAnyOfSeries(this.filters.sharingLabel))
|
if (this.filters.sharingLabel && this.filters.sharingLabel.length > 0) this.filtersMode?.sharingLabel?.allOf ? conditions.push(new SearchConditionAllOfSeries(this.filters.sharingLabel)) : conditions.push(new SearchConditionAnyOfSeries(this.filters.sharingLabel))
|
||||||
if (this.filters.complete && this.filters.complete.length > 0) conditions.push(...this.filters.complete)
|
if (this.filters.complete && this.filters.complete.length > 0) conditions.push(...this.filters.complete)
|
||||||
if (this.filters.oneshot && this.filters.oneshot.length > 0) conditions.push(...this.filters.oneshot)
|
if (this.filters.oneshot && this.filters.oneshot.length > 0) conditions.push(...this.filters.oneshot)
|
||||||
|
if (this.filters.deleted && this.filters.deleted.length > 0) conditions.push(...this.filters.deleted)
|
||||||
authorRoles.forEach((role: string) => {
|
authorRoles.forEach((role: string) => {
|
||||||
if (role in this.filters) {
|
if (role in this.filters) {
|
||||||
const authorConditions = this.filters[role].map((name: string) => {
|
const authorConditions = this.filters[role].map((name: string) => {
|
||||||
|
|
|
||||||
|
|
@ -555,6 +555,7 @@ import {
|
||||||
SearchConditionAnyOfBook,
|
SearchConditionAnyOfBook,
|
||||||
SearchConditionAuthor,
|
SearchConditionAuthor,
|
||||||
SearchConditionBook,
|
SearchConditionBook,
|
||||||
|
SearchConditionDeleted,
|
||||||
SearchConditionGenre,
|
SearchConditionGenre,
|
||||||
SearchConditionLanguage,
|
SearchConditionLanguage,
|
||||||
SearchConditionMediaProfile,
|
SearchConditionMediaProfile,
|
||||||
|
|
@ -564,9 +565,11 @@ import {
|
||||||
SearchConditionSeriesStatus,
|
SearchConditionSeriesStatus,
|
||||||
SearchConditionTag,
|
SearchConditionTag,
|
||||||
SearchOperatorIs,
|
SearchOperatorIs,
|
||||||
|
SearchOperatorIsFalse,
|
||||||
SearchOperatorIsNot,
|
SearchOperatorIsNot,
|
||||||
SearchOperatorIsNotNull,
|
SearchOperatorIsNotNull,
|
||||||
SearchOperatorIsNull,
|
SearchOperatorIsNull,
|
||||||
|
SearchOperatorIsTrue,
|
||||||
} from '@/types/komga-search'
|
} from '@/types/komga-search'
|
||||||
import {objIsEqual} from '@/functions/object'
|
import {objIsEqual} from '@/functions/object'
|
||||||
import i18n from '@/i18n'
|
import i18n from '@/i18n'
|
||||||
|
|
@ -679,6 +682,15 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
deleted: {
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
name: this.$t('common.unavailable').toString(),
|
||||||
|
value: new SearchConditionDeleted(new SearchOperatorIsTrue()),
|
||||||
|
nValue: new SearchConditionDeleted(new SearchOperatorIsFalse()),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
} as FiltersOptions
|
} as FiltersOptions
|
||||||
},
|
},
|
||||||
filterOptionsPanel(): FiltersOptions {
|
filterOptionsPanel(): FiltersOptions {
|
||||||
|
|
@ -874,11 +886,12 @@ export default Vue.extend({
|
||||||
|
|
||||||
// get filter from query params and validate with available filter values
|
// get filter from query params and validate with available filter values
|
||||||
let activeFilters = {} as FiltersActive
|
let activeFilters = {} as FiltersActive
|
||||||
if (route.query.readStatus || route.query.tag || route.query.mediaProfile || authorRoles.some(role => role in route.query)) {
|
if (route.query.readStatus || route.query.tag || route.query.mediaProfile || authorRoles.some(role => role in route.query) || route.query.deleted) {
|
||||||
activeFilters = {
|
activeFilters = {
|
||||||
readStatus: route.query.readStatus || [],
|
readStatus: route.query.readStatus || [],
|
||||||
tag: route.query.tag || [],
|
tag: route.query.tag || [],
|
||||||
mediaProfile: route.query.mediaProfile || [],
|
mediaProfile: route.query.mediaProfile || [],
|
||||||
|
deleted: route.query.deleted || [],
|
||||||
}
|
}
|
||||||
authorRoles.forEach((role: string) => {
|
authorRoles.forEach((role: string) => {
|
||||||
activeFilters[role] = route.query[role] || []
|
activeFilters[role] = route.query[role] || []
|
||||||
|
|
@ -898,6 +911,7 @@ export default Vue.extend({
|
||||||
readStatus: this.$_.intersectionWith(filters.readStatus, extractFilterOptionsValues(this.filterOptionsList.readStatus.values), objIsEqual) || [],
|
readStatus: this.$_.intersectionWith(filters.readStatus, extractFilterOptionsValues(this.filterOptionsList.readStatus.values), objIsEqual) || [],
|
||||||
tag: this.$_.intersectionWith(filters.tag, extractFilterOptionsValues(this.filterOptions.tag), objIsEqual) || [],
|
tag: this.$_.intersectionWith(filters.tag, extractFilterOptionsValues(this.filterOptions.tag), objIsEqual) || [],
|
||||||
mediaProfile: this.$_.intersectionWith(filters.mediaProfile, extractFilterOptionsValues(this.filterOptionsPanel.mediaProfile.values), objIsEqual) || [],
|
mediaProfile: this.$_.intersectionWith(filters.mediaProfile, extractFilterOptionsValues(this.filterOptionsPanel.mediaProfile.values), objIsEqual) || [],
|
||||||
|
deleted: this.$_.intersectionWith(filters.deleted, extractFilterOptionsValues(this.filterOptionsList.deleted.values), objIsEqual) || [],
|
||||||
} as any
|
} as any
|
||||||
authorRoles.forEach((role: string) => {
|
authorRoles.forEach((role: string) => {
|
||||||
validFilter[role] = filters[role] || []
|
validFilter[role] = filters[role] || []
|
||||||
|
|
@ -1039,6 +1053,7 @@ export default Vue.extend({
|
||||||
if (this.filters.readStatus && this.filters.readStatus.length > 0) conditions.push(new SearchConditionAnyOfBook(this.filters.readStatus))
|
if (this.filters.readStatus && this.filters.readStatus.length > 0) conditions.push(new SearchConditionAnyOfBook(this.filters.readStatus))
|
||||||
if (this.filters.tag && this.filters.tag.length > 0) this.filtersMode?.tag?.allOf ? conditions.push(new SearchConditionAllOfBook(this.filters.tag)) : conditions.push(new SearchConditionAnyOfBook(this.filters.tag))
|
if (this.filters.tag && this.filters.tag.length > 0) this.filtersMode?.tag?.allOf ? conditions.push(new SearchConditionAllOfBook(this.filters.tag)) : conditions.push(new SearchConditionAnyOfBook(this.filters.tag))
|
||||||
if (this.filters.mediaProfile && this.filters.mediaProfile.length > 0) this.filtersMode?.mediaProfile?.allOf ? conditions.push(new SearchConditionAllOfBook(this.filters.mediaProfile)) : conditions.push(new SearchConditionAnyOfBook(this.filters.mediaProfile))
|
if (this.filters.mediaProfile && this.filters.mediaProfile.length > 0) this.filtersMode?.mediaProfile?.allOf ? conditions.push(new SearchConditionAllOfBook(this.filters.mediaProfile)) : conditions.push(new SearchConditionAnyOfBook(this.filters.mediaProfile))
|
||||||
|
if (this.filters.deleted && this.filters.deleted.length > 0) conditions.push(...this.filters.deleted)
|
||||||
authorRoles.forEach((role: string) => {
|
authorRoles.forEach((role: string) => {
|
||||||
if (role in this.filters) {
|
if (role in this.filters) {
|
||||||
const authorConditions = this.filters[role].map((name: string) => {
|
const authorConditions = this.filters[role].map((name: string) => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue