Added basic co-star actor filter to actor page.

This commit is contained in:
DebaucheryLibrarian 2020-09-12 03:09:05 +02:00
parent 24fb267b40
commit 62f5d5111a
7 changed files with 155 additions and 6 deletions

View File

@ -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" />

View File

@ -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>

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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,
} }
or: $includedEntities and: [
{
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,
}); });

View File

@ -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,
}; };

View File

@ -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;