forked from DebaucheryLibrarian/traxxx
Added basic co-star actor filter to actor page.
This commit is contained in:
parent
24fb267b40
commit
62f5d5111a
|
@ -297,6 +297,7 @@
|
||||||
:items-per-page="limit"
|
:items-per-page="limit"
|
||||||
:available-tags="actor.tags"
|
:available-tags="actor.tags"
|
||||||
:available-channels="actor.channels"
|
:available-channels="actor.channels"
|
||||||
|
:available-actors="actor.actors"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Releases :releases="releases" />
|
<Releases :releases="releases" />
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
<template>
|
||||||
|
<v-popover class="filter-container">
|
||||||
|
<div class="filter">
|
||||||
|
<Icon icon="users" />
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="selectedActors.length > 0"
|
||||||
|
class="filter-applied"
|
||||||
|
>{{ selectedActors.length }} {{ selectedActors.length > 1 ? 'actors' : 'actor' }}</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="filter-applied empty"
|
||||||
|
>Actors</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div slot="popover">
|
||||||
|
<router-link
|
||||||
|
class="filter-clear"
|
||||||
|
:to="{ query: { ...$route.query, actors: undefined } }"
|
||||||
|
:class="{ active: selectedActors.length > 0 }"
|
||||||
|
>clear all<Icon icon="cross2" /></router-link>
|
||||||
|
|
||||||
|
<ul class="filter-items nolist">
|
||||||
|
<li
|
||||||
|
v-for="actor in availableActors"
|
||||||
|
:key="actor.id"
|
||||||
|
class="filter-item"
|
||||||
|
:class="{ selected: selectedActors.includes(actor.slug) }"
|
||||||
|
>
|
||||||
|
<router-link
|
||||||
|
:to="{ query: {
|
||||||
|
...$route.query,
|
||||||
|
actors: actor.slug,
|
||||||
|
}, params: { pageNumber: 1 } }"
|
||||||
|
class="filter-name"
|
||||||
|
>{{ actor.name }}</router-link>
|
||||||
|
|
||||||
|
<router-link
|
||||||
|
:to="{ query: { ...$route.query, ...getNewRange(actor) }, params: { pageNumber: 1 } }"
|
||||||
|
class="filter-include"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
icon="checkmark"
|
||||||
|
class="filter-add"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Icon
|
||||||
|
icon="cross2"
|
||||||
|
class="filter-remove"
|
||||||
|
/>
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</v-popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function getNewRange(actor) {
|
||||||
|
if (this.selectedActors.includes(actor.slug)) {
|
||||||
|
return { actors: this.selectedActors.filter(selectedActor => selectedActor !== actor.slug).join(',') || undefined };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { actors: this.selectedActors.concat(actor.slug).join(',') };
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectedActors() {
|
||||||
|
return this.$route.query.actors ? this.$route.query.actors.split(',') : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
availableActors: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
selectedActors,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getNewRange,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -42,7 +42,7 @@
|
||||||
class="filter-name"
|
class="filter-name"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
v-if="channel.independent || !channel.parent"
|
v-if="channel.type === 'network' || channel.independent || !channel.parent "
|
||||||
:src="`/img/logos/${channel.slug}/favicon.png`"
|
:src="`/img/logos/${channel.slug}/favicon.png`"
|
||||||
class="favicon"
|
class="favicon"
|
||||||
>
|
>
|
||||||
|
@ -109,7 +109,7 @@ function selectedNetworks() {
|
||||||
|
|
||||||
function channelsPerNetwork() {
|
function channelsPerNetwork() {
|
||||||
const networks = this.availableChannels.reduce((acc, channel) => {
|
const networks = this.availableChannels.reduce((acc, channel) => {
|
||||||
if (channel.independent || !channel.parent) {
|
if (channel.type === 'network' || channel.independent || !channel.parent) {
|
||||||
acc[channel.slug] = { ...channel, children: [] };
|
acc[channel.slug] = { ...channel, children: [] };
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,12 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="filters">
|
<div class="filters">
|
||||||
|
<ActorFilter
|
||||||
|
class="filters-filter"
|
||||||
|
:filter="filter"
|
||||||
|
:available-actors="availableActors"
|
||||||
|
/>
|
||||||
|
|
||||||
<ChannelFilter
|
<ChannelFilter
|
||||||
class="filters-filter"
|
class="filters-filter"
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
|
@ -38,6 +44,8 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex';
|
||||||
|
|
||||||
|
import ActorFilter from './actor-filter.vue';
|
||||||
import ChannelFilter from './channel-filter.vue';
|
import ChannelFilter from './channel-filter.vue';
|
||||||
import TagFilter from './tag-filter.vue';
|
import TagFilter from './tag-filter.vue';
|
||||||
|
|
||||||
|
@ -67,6 +75,7 @@ async function setBatch(newBatch) {
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
ActorFilter,
|
||||||
ChannelFilter,
|
ChannelFilter,
|
||||||
TagFilter,
|
TagFilter,
|
||||||
},
|
},
|
||||||
|
@ -95,6 +104,10 @@ export default {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
|
availableActors: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
|
@ -253,7 +266,7 @@ export default {
|
||||||
background: var(--darken-hint);
|
background: var(--darken-hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media(max-width: $breakpoint-micro) {
|
@media(max-width: $breakpoint-small) {
|
||||||
.filter-applied {
|
.filter-applied {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import config from 'config';
|
import config from 'config';
|
||||||
import { graphql, get } from '../api';
|
import { graphql, get } from '../api';
|
||||||
import { releaseFields, getIncludedEntities } from '../fragments';
|
import { releaseFields, getIncludedEntities, getIncludedActors } from '../fragments';
|
||||||
import { curateActor, curateRelease } from '../curate';
|
import { curateActor, curateRelease } from '../curate';
|
||||||
import getDateRange from '../get-date-range';
|
import getDateRange from '../get-date-range';
|
||||||
|
|
||||||
|
@ -26,7 +26,8 @@ function initActorActions(store, router) {
|
||||||
$selectableTags: [String],
|
$selectableTags: [String],
|
||||||
$includedTags: [String!],
|
$includedTags: [String!],
|
||||||
$mode: String!,
|
$mode: String!,
|
||||||
$includedEntities: [ReleaseFilter!]
|
$includedEntities: [ReleaseFilter!],
|
||||||
|
$includedActors: [ReleaseFilter!]
|
||||||
) {
|
) {
|
||||||
actor(id: $actorId) {
|
actor(id: $actorId) {
|
||||||
id
|
id
|
||||||
|
@ -160,13 +161,25 @@ function initActorActions(store, router) {
|
||||||
type
|
type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
actors {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
}
|
||||||
scenesConnection(
|
scenesConnection(
|
||||||
filter: {
|
filter: {
|
||||||
date: {
|
date: {
|
||||||
lessThan: $before,
|
lessThan: $before,
|
||||||
greaterThan: $after,
|
greaterThan: $after,
|
||||||
}
|
}
|
||||||
|
and: [
|
||||||
|
{
|
||||||
or: $includedEntities
|
or: $includedEntities
|
||||||
|
}
|
||||||
|
{
|
||||||
|
or: $includedActors
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
selectedTags: $includedTags
|
selectedTags: $includedTags
|
||||||
mode: $mode
|
mode: $mode
|
||||||
|
@ -192,6 +205,7 @@ function initActorActions(store, router) {
|
||||||
excludeTags: store.state.ui.filter,
|
excludeTags: store.state.ui.filter,
|
||||||
includedTags,
|
includedTags,
|
||||||
includedEntities: getIncludedEntities(router),
|
includedEntities: getIncludedEntities(router),
|
||||||
|
includedActors: getIncludedActors(router),
|
||||||
mode,
|
mode,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -360,6 +360,27 @@ function getIncludedEntities(router) {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getIncludedActors(router) {
|
||||||
|
const includedActors = router.currentRoute.query.actors ? router.currentRoute.query.actors.split(',') : [];
|
||||||
|
|
||||||
|
if (includedActors.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
releasesActorsConnection: {
|
||||||
|
some: {
|
||||||
|
actor: {
|
||||||
|
slug: {
|
||||||
|
in: includedActors,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
releaseActorsFragment,
|
releaseActorsFragment,
|
||||||
|
@ -373,4 +394,5 @@ export {
|
||||||
siteFragment,
|
siteFragment,
|
||||||
sitesFragment,
|
sitesFragment,
|
||||||
getIncludedEntities,
|
getIncludedEntities,
|
||||||
|
getIncludedActors,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1004,6 +1004,17 @@ exports.up = knex => Promise.resolve()
|
||||||
GROUP BY entities.id;
|
GROUP BY entities.id;
|
||||||
$$ LANGUAGE SQL STABLE;
|
$$ LANGUAGE SQL STABLE;
|
||||||
|
|
||||||
|
CREATE FUNCTION actors_actors(actor actors) RETURNS SETOF actors AS $$
|
||||||
|
SELECT actors.*
|
||||||
|
FROM releases_actors
|
||||||
|
LEFT JOIN releases_actors AS associated_actors ON associated_actors.release_id = releases_actors.release_id
|
||||||
|
LEFT JOIN actors ON actors.id = associated_actors.actor_id
|
||||||
|
WHERE releases_actors.actor_id = actor.id
|
||||||
|
AND NOT actors.id = actor.id
|
||||||
|
GROUP BY actors.id
|
||||||
|
ORDER BY actors.name;
|
||||||
|
$$ LANGUAGE SQL STABLE;
|
||||||
|
|
||||||
/* GraphQL/Postgraphile 'every' applies to the data, will only include scenes for which every assigned tag is selected,
|
/* GraphQL/Postgraphile 'every' applies to the data, will only include scenes for which every assigned tag is selected,
|
||||||
instead of what we want; scenes with every selected tag, but possibly also some others */
|
instead of what we want; scenes with every selected tag, but possibly also some others */
|
||||||
CREATE FUNCTION actors_scenes(actor actors, selected_tags text[], mode text DEFAULT 'all') RETURNS SETOF releases AS $$
|
CREATE FUNCTION actors_scenes(actor actors, selected_tags text[], mode text DEFAULT 'all') RETURNS SETOF releases AS $$
|
||||||
|
@ -1108,6 +1119,7 @@ exports.up = knex => Promise.resolve()
|
||||||
|
|
||||||
COMMENT ON FUNCTION actors_tags IS E'@sortable';
|
COMMENT ON FUNCTION actors_tags IS E'@sortable';
|
||||||
COMMENT ON FUNCTION actors_channels IS E'@sortable';
|
COMMENT ON FUNCTION actors_channels IS E'@sortable';
|
||||||
|
COMMENT ON FUNCTION actors_actors IS E'@sortable';
|
||||||
COMMENT ON FUNCTION actors_scenes IS E'@sortable';
|
COMMENT ON FUNCTION actors_scenes IS E'@sortable';
|
||||||
|
|
||||||
COMMENT ON FUNCTION tags_scenes IS E'@sortable';
|
COMMENT ON FUNCTION tags_scenes IS E'@sortable';
|
||||||
|
@ -1179,6 +1191,7 @@ exports.down = (knex) => { // eslint-disable-line arrow-body-style
|
||||||
DROP FUNCTION IF EXISTS releases_is_new;
|
DROP FUNCTION IF EXISTS releases_is_new;
|
||||||
DROP FUNCTION IF EXISTS actors_tags;
|
DROP FUNCTION IF EXISTS actors_tags;
|
||||||
DROP FUNCTION IF EXISTS actors_channels;
|
DROP FUNCTION IF EXISTS actors_channels;
|
||||||
|
DROP FUNCTION IF EXISTS actors_actors;
|
||||||
DROP FUNCTION IF EXISTS actors_scenes;
|
DROP FUNCTION IF EXISTS actors_scenes;
|
||||||
|
|
||||||
DROP FUNCTION IF EXISTS movies_actors;
|
DROP FUNCTION IF EXISTS movies_actors;
|
||||||
|
|
Loading…
Reference in New Issue