diff --git a/assets/components/actors/actor.vue b/assets/components/actors/actor.vue
index 164fe42e..dc42be69 100644
--- a/assets/components/actors/actor.vue
+++ b/assets/components/actors/actor.vue
@@ -297,6 +297,7 @@
:items-per-page="limit"
:available-tags="actor.tags"
:available-channels="actor.channels"
+ :available-actors="actor.actors"
/>
diff --git a/assets/components/filters/actor-filter.vue b/assets/components/filters/actor-filter.vue
new file mode 100644
index 00000000..a3bd3efa
--- /dev/null
+++ b/assets/components/filters/actor-filter.vue
@@ -0,0 +1,86 @@
+
+
+
+
+
+
{{ selectedActors.length }} {{ selectedActors.length > 1 ? 'actors' : 'actor' }}
+
+
Actors
+
+
+
+
clear all
+
+
+ -
+ {{ actor.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/components/filters/channel-filter.vue b/assets/components/filters/channel-filter.vue
index 8df6c133..52721387 100644
--- a/assets/components/filters/channel-filter.vue
+++ b/assets/components/filters/channel-filter.vue
@@ -42,7 +42,7 @@
class="filter-name"
>
@@ -109,7 +109,7 @@ function selectedNetworks() {
function channelsPerNetwork() {
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: [] };
return acc;
}
diff --git a/assets/components/filters/filter-bar.vue b/assets/components/filters/filter-bar.vue
index 53edb738..67de1b1f 100644
--- a/assets/components/filters/filter-bar.vue
+++ b/assets/components/filters/filter-bar.vue
@@ -21,6 +21,12 @@
+
+
import { mapState } from 'vuex';
+
+import ActorFilter from './actor-filter.vue';
import ChannelFilter from './channel-filter.vue';
import TagFilter from './tag-filter.vue';
@@ -67,6 +75,7 @@ async function setBatch(newBatch) {
export default {
components: {
+ ActorFilter,
ChannelFilter,
TagFilter,
},
@@ -95,6 +104,10 @@ export default {
type: Array,
default: () => [],
},
+ availableActors: {
+ type: Array,
+ default: () => [],
+ },
},
computed: {
...mapState({
@@ -253,7 +266,7 @@ export default {
background: var(--darken-hint);
}
-@media(max-width: $breakpoint-micro) {
+@media(max-width: $breakpoint-small) {
.filter-applied {
display: none;
}
diff --git a/assets/js/actors/actions.js b/assets/js/actors/actions.js
index e46e4b5a..e54759f1 100644
--- a/assets/js/actors/actions.js
+++ b/assets/js/actors/actions.js
@@ -1,6 +1,6 @@
import config from 'config';
import { graphql, get } from '../api';
-import { releaseFields, getIncludedEntities } from '../fragments';
+import { releaseFields, getIncludedEntities, getIncludedActors } from '../fragments';
import { curateActor, curateRelease } from '../curate';
import getDateRange from '../get-date-range';
@@ -26,7 +26,8 @@ function initActorActions(store, router) {
$selectableTags: [String],
$includedTags: [String!],
$mode: String!,
- $includedEntities: [ReleaseFilter!]
+ $includedEntities: [ReleaseFilter!],
+ $includedActors: [ReleaseFilter!]
) {
actor(id: $actorId) {
id
@@ -160,13 +161,25 @@ function initActorActions(store, router) {
type
}
}
+ actors {
+ id
+ name
+ slug
+ }
scenesConnection(
filter: {
date: {
lessThan: $before,
greaterThan: $after,
}
- or: $includedEntities
+ and: [
+ {
+ or: $includedEntities
+ }
+ {
+ or: $includedActors
+ }
+ ]
}
selectedTags: $includedTags
mode: $mode
@@ -192,6 +205,7 @@ function initActorActions(store, router) {
excludeTags: store.state.ui.filter,
includedTags,
includedEntities: getIncludedEntities(router),
+ includedActors: getIncludedActors(router),
mode,
});
diff --git a/assets/js/fragments.js b/assets/js/fragments.js
index 0e9dd2bf..151db959 100644
--- a/assets/js/fragments.js
+++ b/assets/js/fragments.js
@@ -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 {
releaseActorsFragment,
@@ -373,4 +394,5 @@ export {
siteFragment,
sitesFragment,
getIncludedEntities,
+ getIncludedActors,
};
diff --git a/migrations/20190325001339_releases.js b/migrations/20190325001339_releases.js
index fec78fc0..77778c88 100644
--- a/migrations/20190325001339_releases.js
+++ b/migrations/20190325001339_releases.js
@@ -1004,6 +1004,17 @@ exports.up = knex => Promise.resolve()
GROUP BY entities.id;
$$ 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,
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 $$
@@ -1108,6 +1119,7 @@ exports.up = knex => Promise.resolve()
COMMENT ON FUNCTION actors_tags 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 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 actors_tags;
DROP FUNCTION IF EXISTS actors_channels;
+ DROP FUNCTION IF EXISTS actors_actors;
DROP FUNCTION IF EXISTS actors_scenes;
DROP FUNCTION IF EXISTS movies_actors;