From b172d678faa59a2694b5ba8c898d48c7396d6495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=AD=C3=B0ir=20Valberg=20Gu=C3=B0mundsson?= Date: Sun, 20 May 2018 20:08:25 +0200 Subject: [PATCH] Add filter for tracks to the schedule --- schedule/src/Decoders.elm | 9 ++ schedule/src/Main.elm | 4 +- schedule/src/Models.elm | 7 ++ schedule/src/Update.elm | 13 +++ schedule/src/Views/FilterView.elm | 14 +++ src/program/consumers.py | 10 ++ src/program/models.py | 7 ++ src/program/static/js/elm_based_schedule.js | 123 ++++++++++++++------ 8 files changed, 151 insertions(+), 36 deletions(-) diff --git a/schedule/src/Decoders.elm b/schedule/src/Decoders.elm index b574794c..b0f75be7 100644 --- a/schedule/src/Decoders.elm +++ b/schedule/src/Decoders.elm @@ -82,6 +82,7 @@ eventInstanceDecoder = |> required "url" string |> required "event_slug" string |> required "event_type" string + |> required "event_track" string |> required "bg-color" string |> required "fg-color" string |> required "from" dateDecoder @@ -111,6 +112,13 @@ eventTypeDecoder = |> required "light_text" bool +eventTrackDecoder : Decoder FilterType +eventTrackDecoder = + decode TrackFilter + |> required "name" string + |> required "slug" string + + initDataDecoder : Decoder (Flags -> Filter -> Location -> Route -> Bool -> Model) initDataDecoder = decode Model @@ -119,4 +127,5 @@ initDataDecoder = |> required "event_instances" (list eventInstanceDecoder) |> required "event_locations" (list eventLocationDecoder) |> required "event_types" (list eventTypeDecoder) + |> required "event_tracks" (list eventTrackDecoder) |> required "speakers" (list speakerDecoder) diff --git a/schedule/src/Main.elm b/schedule/src/Main.elm index 7b03faeb..b165e2f0 100644 --- a/schedule/src/Main.elm +++ b/schedule/src/Main.elm @@ -34,10 +34,10 @@ init flags location = parseLocation location emptyFilter = - Filter [] [] [] + Filter [] [] [] [] model = - Model [] [] [] [] [] [] flags emptyFilter location currentRoute False + Model [] [] [] [] [] [] [] flags emptyFilter location currentRoute False in model ! [ sendInitMessage flags.camp_slug flags.websocket_server ] diff --git a/schedule/src/Models.elm b/schedule/src/Models.elm index 9f60f394..b9f37ed3 100644 --- a/schedule/src/Models.elm +++ b/schedule/src/Models.elm @@ -49,6 +49,7 @@ type alias Model = , eventInstances : List EventInstance , eventLocations : List FilterType , eventTypes : List FilterType + , eventTracks : List FilterType , speakers : List Speaker , flags : Flags , filter : Filter @@ -81,6 +82,7 @@ type alias EventInstance = , url : String , eventSlug : EventSlug , eventType : String + , eventTrack : String , backgroundColor : String , forgroundColor : String , from : Date @@ -142,11 +144,13 @@ type FilterType = TypeFilter FilterName FilterSlug TypeColor TypeLightText | LocationFilter FilterName FilterSlug LocationIcon | VideoFilter FilterName FilterSlug + | TrackFilter FilterName FilterSlug type alias Filter = { eventTypes : List FilterType , eventLocations : List FilterType + , eventTracks : List FilterType , videoRecording : List FilterType } @@ -162,6 +166,9 @@ unpackFilterType filter = VideoFilter name slug -> ( name, slug ) + TrackFilter name slug -> + ( name, slug ) + getSlugFromFilterType filter = let diff --git a/schedule/src/Update.elm b/schedule/src/Update.elm index 8d2ad964..720cea93 100644 --- a/schedule/src/Update.elm +++ b/schedule/src/Update.elm @@ -96,6 +96,19 @@ update msg model = videoRecording :: model.filter.videoRecording } + TrackFilter name slug -> + let + eventTrack = + TrackFilter name slug + in + { currentFilter + | eventTracks = + if List.member eventTrack model.filter.eventTracks then + List.filter (\x -> x /= eventTrack) model.filter.videoRecording + else + eventTrack :: model.filter.eventTracks + } + query = filterToQuery newFilter diff --git a/schedule/src/Views/FilterView.elm b/schedule/src/Views/FilterView.elm index 8a641868..6cfd6093 100644 --- a/schedule/src/Views/FilterView.elm +++ b/schedule/src/Views/FilterView.elm @@ -37,6 +37,9 @@ applyFilters day model = locations = slugs model.eventLocations model.filter.eventLocations + tracks = + slugs model.eventTracks model.filter.eventTracks + videoFilters = slugs videoRecordingFilters model.filter.videoRecording @@ -47,6 +50,7 @@ applyFilters day model = && (Date.Extra.equalBy Date.Extra.Day eventInstance.from day.date) && List.member eventInstance.location locations && List.member eventInstance.eventType types + && List.member eventInstance.eventTrack tracks && List.member eventInstance.videoState videoFilters ) model.eventInstances @@ -77,6 +81,12 @@ filterSidebar model = model.filter.eventLocations model.eventInstances .location + , filterView + "Track" + model.eventTracks + model.filter.eventTracks + model.eventInstances + .eventTrack , filterView "Video" videoRecordingFilters @@ -309,11 +319,15 @@ parseFilterFromQuery query model = locations = getFilter "location" model.eventLocations query + tracks = + getFilter "tracks" model.eventTracks query + videoFilters = getFilter "video" videoRecordingFilters query in { eventTypes = types , eventLocations = locations + , eventTracks = tracks , videoRecording = videoFilters } diff --git a/src/program/consumers.py b/src/program/consumers.py index c325a0df..c4bdeaaa 100644 --- a/src/program/consumers.py +++ b/src/program/consumers.py @@ -7,6 +7,7 @@ from .models import ( Favorite, EventLocation, EventType, + EventTrack, Speaker ) @@ -59,6 +60,14 @@ class ScheduleConsumer(JsonWebsocketConsumer): for x in event_types_query_set ]) + event_tracks_query_set = EventTrack.objects.filter( + camp=camp + ) + event_tracks = list([ + x.serialize() + for x in event_tracks_query_set + ]) + speakers_query_set = Speaker.objects.filter(camp=camp) speakers = list([x.serialize() for x in speakers_query_set]) @@ -68,6 +77,7 @@ class ScheduleConsumer(JsonWebsocketConsumer): "event_instances": event_instances, "event_locations": event_locations, "event_types": event_types, + "event_tracks": event_tracks, "speakers": speakers, "days": days, } diff --git a/src/program/models.py b/src/program/models.py index 5f4bd6ed..fd4a8164 100644 --- a/src/program/models.py +++ b/src/program/models.py @@ -258,6 +258,12 @@ class EventTrack(CampRelatedModel): class Meta: unique_together = (('camp', 'slug'), ('camp', 'name')) + def serialize(self): + return { + "name": self.name, + "slug": self.slug, + } + class EventLocation(CampRelatedModel): """ The places where stuff happens """ @@ -533,6 +539,7 @@ class EventInstance(CampRelatedModel): 'bg-color': self.event.event_type.color, 'fg-color': '#fff' if self.event.event_type.light_text else '#000', 'event_type': self.event.event_type.slug, + 'event_track': self.event.track.slug, 'location': self.location.slug, 'location_icon': self.location.icon, 'timeslots': self.timeslots, diff --git a/src/program/static/js/elm_based_schedule.js b/src/program/static/js/elm_based_schedule.js index 5e27d676..7243619b 100644 --- a/src/program/static/js/elm_based_schedule.js +++ b/src/program/static/js/elm_based_schedule.js @@ -13879,6 +13879,8 @@ var _user$project$Models$unpackFilterType = function (filter) { return {ctor: '_Tuple2', _0: _p0._0, _1: _p0._1}; case 'LocationFilter': return {ctor: '_Tuple2', _0: _p0._0, _1: _p0._1}; + case 'VideoFilter': + return {ctor: '_Tuple2', _0: _p0._0, _1: _p0._1}; default: return {ctor: '_Tuple2', _0: _p0._0, _1: _p0._1}; } @@ -13905,7 +13907,9 @@ var _user$project$Models$Model = function (a) { return function (i) { return function (j) { return function (k) { - return {days: a, events: b, eventInstances: c, eventLocations: d, eventTypes: e, speakers: f, flags: g, filter: h, location: i, route: j, dataLoaded: k}; + return function (l) { + return {days: a, events: b, eventInstances: c, eventLocations: d, eventTypes: e, eventTracks: f, speakers: g, flags: h, filter: i, location: j, route: k, dataLoaded: l}; + }; }; }; }; @@ -13941,7 +13945,9 @@ var _user$project$Models$EventInstance = function (a) { return function (n) { return function (o) { return function (p) { - return {title: a, slug: b, id: c, url: d, eventSlug: e, eventType: f, backgroundColor: g, forgroundColor: h, from: i, to: j, timeslots: k, location: l, locationIcon: m, videoState: n, videoUrl: o, isFavorited: p}; + return function (q) { + return {title: a, slug: b, id: c, url: d, eventSlug: e, eventType: f, eventTrack: g, backgroundColor: h, forgroundColor: i, from: j, to: k, timeslots: l, location: m, locationIcon: n, videoState: o, videoUrl: p, isFavorited: q}; + }; }; }; }; @@ -13966,9 +13972,9 @@ var _user$project$Models$Flags = F5( function (a, b, c, d, e) { return {schedule_timeslot_length_minutes: a, schedule_midnight_offset_hours: b, ics_button_href: c, camp_slug: d, websocket_server: e}; }); -var _user$project$Models$Filter = F3( - function (a, b, c) { - return {eventTypes: a, eventLocations: b, videoRecording: c}; +var _user$project$Models$Filter = F4( + function (a, b, c, d) { + return {eventTypes: a, eventLocations: b, eventTracks: c, videoRecording: d}; }); var _user$project$Models$NotFoundRoute = {ctor: 'NotFoundRoute'}; var _user$project$Models$SpeakerRoute = function (a) { @@ -13984,6 +13990,10 @@ var _user$project$Models$OverviewFilteredRoute = function (a) { return {ctor: 'OverviewFilteredRoute', _0: a}; }; var _user$project$Models$OverviewRoute = {ctor: 'OverviewRoute'}; +var _user$project$Models$TrackFilter = F2( + function (a, b) { + return {ctor: 'TrackFilter', _0: a, _1: b}; + }); var _user$project$Models$VideoFilter = F2( function (a, b) { return {ctor: 'VideoFilter', _0: a, _1: b}; @@ -13997,6 +14007,15 @@ var _user$project$Models$TypeFilter = F4( return {ctor: 'TypeFilter', _0: a, _1: b, _2: c, _3: d}; }); +var _user$project$Decoders$eventTrackDecoder = A3( + _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, + 'slug', + _elm_lang$core$Json_Decode$string, + A3( + _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, + 'name', + _elm_lang$core$Json_Decode$string, + _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$decode(_user$project$Models$TrackFilter))); var _user$project$Decoders$eventTypeDecoder = A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, 'light_text', @@ -14080,29 +14099,33 @@ var _user$project$Decoders$eventInstanceDecoder = A4( _elm_lang$core$Json_Decode$string, A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, - 'event_type', + 'event_track', _elm_lang$core$Json_Decode$string, A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, - 'event_slug', + 'event_type', _elm_lang$core$Json_Decode$string, A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, - 'url', + 'event_slug', _elm_lang$core$Json_Decode$string, A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, - 'id', - _elm_lang$core$Json_Decode$int, + 'url', + _elm_lang$core$Json_Decode$string, A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, - 'slug', - _elm_lang$core$Json_Decode$string, + 'id', + _elm_lang$core$Json_Decode$int, A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, - 'title', + 'slug', _elm_lang$core$Json_Decode$string, - _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$decode(_user$project$Models$EventInstance))))))))))))))))); + A3( + _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, + 'title', + _elm_lang$core$Json_Decode$string, + _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$decode(_user$project$Models$EventInstance)))))))))))))))))); var _user$project$Decoders$eventDecoder = A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, 'event_type', @@ -14175,25 +14198,29 @@ var _user$project$Decoders$initDataDecoder = A3( _elm_lang$core$Json_Decode$list(_user$project$Decoders$speakerDecoder), A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, - 'event_types', - _elm_lang$core$Json_Decode$list(_user$project$Decoders$eventTypeDecoder), + 'event_tracks', + _elm_lang$core$Json_Decode$list(_user$project$Decoders$eventTrackDecoder), A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, - 'event_locations', - _elm_lang$core$Json_Decode$list(_user$project$Decoders$eventLocationDecoder), + 'event_types', + _elm_lang$core$Json_Decode$list(_user$project$Decoders$eventTypeDecoder), A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, - 'event_instances', - _elm_lang$core$Json_Decode$list(_user$project$Decoders$eventInstanceDecoder), + 'event_locations', + _elm_lang$core$Json_Decode$list(_user$project$Decoders$eventLocationDecoder), A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, - 'events', - _elm_lang$core$Json_Decode$list(_user$project$Decoders$eventDecoder), + 'event_instances', + _elm_lang$core$Json_Decode$list(_user$project$Decoders$eventInstanceDecoder), A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, - 'days', - _elm_lang$core$Json_Decode$list(_user$project$Decoders$dayDecoder), - _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$decode(_user$project$Models$Model))))))); + 'events', + _elm_lang$core$Json_Decode$list(_user$project$Decoders$eventDecoder), + A3( + _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, + 'days', + _elm_lang$core$Json_Decode$list(_user$project$Decoders$dayDecoder), + _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$decode(_user$project$Models$Model)))))))); var _user$project$Decoders$WebSocketAction = function (a) { return {action: a}; }; @@ -14709,9 +14736,10 @@ var _user$project$Views_FilterView$videoRecordingFilters = { var _user$project$Views_FilterView$parseFilterFromQuery = F2( function (query, model) { var videoFilters = A3(_user$project$Views_FilterView$getFilter, 'video', _user$project$Views_FilterView$videoRecordingFilters, query); + var tracks = A3(_user$project$Views_FilterView$getFilter, 'tracks', model.eventTracks, query); var locations = A3(_user$project$Views_FilterView$getFilter, 'location', model.eventLocations, query); var types = A3(_user$project$Views_FilterView$getFilter, 'type', model.eventTypes, query); - return {eventTypes: types, eventLocations: locations, videoRecording: videoFilters}; + return {eventTypes: types, eventLocations: locations, eventTracks: tracks, videoRecording: videoFilters}; }); var _user$project$Views_FilterView$icsButton = function (model) { var filterString = function () { @@ -14835,14 +14863,26 @@ var _user$project$Views_FilterView$filterSidebar = function (model) { ctor: '::', _0: A5( _user$project$Views_FilterView$filterView, - 'Video', - _user$project$Views_FilterView$videoRecordingFilters, - model.filter.videoRecording, + 'Track', + model.eventTracks, + model.filter.eventTracks, model.eventInstances, function (_) { - return _.videoState; + return _.eventTrack; }), - _1: {ctor: '[]'} + _1: { + ctor: '::', + _0: A5( + _user$project$Views_FilterView$filterView, + 'Video', + _user$project$Views_FilterView$videoRecordingFilters, + model.filter.videoRecording, + model.eventInstances, + function (_) { + return _.videoState; + }), + _1: {ctor: '[]'} + } } } }), @@ -14865,11 +14905,12 @@ var _user$project$Views_FilterView$applyFilters = F2( }); var types = A2(slugs, model.eventTypes, model.filter.eventTypes); var locations = A2(slugs, model.eventLocations, model.filter.eventLocations); + var tracks = A2(slugs, model.eventTracks, model.filter.eventTracks); var videoFilters = A2(slugs, _user$project$Views_FilterView$videoRecordingFilters, model.filter.videoRecording); var filteredEventInstances = A2( _elm_lang$core$List$filter, function (eventInstance) { - return A3(_justinmimbs$elm_date_extra$Date_Extra$equalBy, _justinmimbs$elm_date_extra$Date_Extra$Month, eventInstance.from, day.date) && (A3(_justinmimbs$elm_date_extra$Date_Extra$equalBy, _justinmimbs$elm_date_extra$Date_Extra$Day, eventInstance.from, day.date) && (A2(_elm_lang$core$List$member, eventInstance.location, locations) && (A2(_elm_lang$core$List$member, eventInstance.eventType, types) && A2(_elm_lang$core$List$member, eventInstance.videoState, videoFilters)))); + return A3(_justinmimbs$elm_date_extra$Date_Extra$equalBy, _justinmimbs$elm_date_extra$Date_Extra$Month, eventInstance.from, day.date) && (A3(_justinmimbs$elm_date_extra$Date_Extra$equalBy, _justinmimbs$elm_date_extra$Date_Extra$Day, eventInstance.from, day.date) && (A2(_elm_lang$core$List$member, eventInstance.location, locations) && (A2(_elm_lang$core$List$member, eventInstance.eventType, types) && (A2(_elm_lang$core$List$member, eventInstance.eventTrack, tracks) && A2(_elm_lang$core$List$member, eventInstance.videoState, videoFilters))))); }, model.eventInstances); return filteredEventInstances; @@ -14939,7 +14980,7 @@ var _user$project$Update$update = F2( }, model.filter.eventLocations) : {ctor: '::', _0: eventLocation, _1: model.filter.eventLocations} }); - default: + case 'VideoFilter': var videoRecording = A2(_user$project$Models$VideoFilter, _p6._0, _p6._1); return _elm_lang$core$Native_Utils.update( currentFilter, @@ -14951,6 +14992,18 @@ var _user$project$Update$update = F2( }, model.filter.videoRecording) : {ctor: '::', _0: videoRecording, _1: model.filter.videoRecording} }); + default: + var eventTrack = A2(_user$project$Models$TrackFilter, _p6._0, _p6._1); + return _elm_lang$core$Native_Utils.update( + currentFilter, + { + eventTracks: A2(_elm_lang$core$List$member, eventTrack, model.filter.eventTracks) ? A2( + _elm_lang$core$List$filter, + function (x) { + return !_elm_lang$core$Native_Utils.eq(x, eventTrack); + }, + model.filter.videoRecording) : {ctor: '::', _0: eventTrack, _1: model.filter.eventTracks} + }); } }(); var query = _user$project$Views_FilterView$filterToQuery(newFilter); @@ -16690,10 +16743,11 @@ var _user$project$Main$subscriptions = function (model) { }; var _user$project$Main$init = F2( function (flags, location) { - var emptyFilter = A3( + var emptyFilter = A4( _user$project$Models$Filter, {ctor: '[]'}, {ctor: '[]'}, + {ctor: '[]'}, {ctor: '[]'}); var currentRoute = _user$project$Routing$parseLocation(location); var model = _user$project$Models$Model( @@ -16702,6 +16756,7 @@ var _user$project$Main$init = F2( {ctor: '[]'})( {ctor: '[]'})( {ctor: '[]'})( + {ctor: '[]'})( {ctor: '[]'})(flags)(emptyFilter)(location)(currentRoute)(false); return A2( _elm_lang$core$Platform_Cmd_ops['!'],