Skip to content

Commit

Permalink
Make scorings and comparison tables first-class, with the ability to …
Browse files Browse the repository at this point in the history
…delete them.

PP-80, PP-81
  • Loading branch information
lo5 committed May 7, 2014
1 parent e09a723 commit 38713f2
Show file tree
Hide file tree
Showing 17 changed files with 290 additions and 183 deletions.
5 changes: 5 additions & 0 deletions client/src/scripts/application-context.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,15 @@ Steam.ApplicationContext = ->
displayNotification: do edge$

loadScorings: do edge$
scoringsLoaded: do edge$
displayScoring: do edge$
scoringSelectionChanged: do edge$
scoringSelectionCleared: do edge$
scoringsSelected: do edge$
scoringsDeselected: do edge$
deselectAllScorings: do edge$
clearScoringSelection: do edge$
deleteScorings: do edge$
deleteActiveScoring: do edge$


39 changes: 25 additions & 14 deletions client/src/scripts/main-view.coffee
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Steam.MainView = (_) ->
_listViews = nodes$ []
_selectionViews = node$ []
_pageViews = nodes$ []
_modalViews = nodes$ []
_isModal = lift$ _modalViews, (modalViews) -> modalViews.length > 0
Expand Down Expand Up @@ -29,19 +30,23 @@ Steam.MainView = (_) ->
when _frameTopic
unless _topic() is topic
_topic topic
switchList _frameListView
switchListView _frameListView
switchSelectionView null
when _modelTopic
unless _topic() is topic
_topic topic
switchList _modelListView
switchListView _modelListView
switchSelectionView null
when _scoringTopic
unless _topic() is topic
_topic topic
switchList _scoringListView
switchListView _scoringListView
switchSelectionView _scoringSelectionView
when _notificationTopic
unless _topic() is topic
_topic topic
switchList _notificationListView
switchListView _notificationListView
switchSelectionView null
_isDisplayingTopics no
return

Expand Down Expand Up @@ -72,41 +77,46 @@ Steam.MainView = (_) ->
_administrationTopic = createTopic 'Administration', null
]

# List views
_topicListView = Steam.TopicListView _, _topics
_frameListView = Steam.FrameListView _
_modelListView = Steam.ModelListView _
_scoringListView = Steam.ScoringListView _
_notificationListView = Steam.NotificationListView _

# Selection views
_modelSelectionView = Steam.ModelSelectionView _
_scoringSelectionView = Steam.ScoringSelectionView _

switchView = (views, view) ->
for oldView in views()
oldView.dispose() if isFunction oldView.dispose
if view
views [ view ]
else
views.removeAll()
views []

switchList = (view) -> switchView _listViews, view
switchPage = (view) -> switchView _pageViews, view
switchModal = (view) -> switchView _modalViews, view
switchListView = (view) -> switchView _listViews, view
switchSelectionView = (view) -> switchView _selectionViews, view
switchPageView = (view) -> switchView _pageViews, view
switchModalView = (view) -> switchView _modalViews, view

_template = (view) -> view.template

link$ _.displayEmpty, ->
switchPage template: 'empty-view'
switchPageView template: 'empty-view'

link$ _.displayFrame, (frame) ->
switchPage Steam.FrameView _, frame if _topic() is _frameTopic
switchPageView Steam.FrameView _, frame if _topic() is _frameTopic

link$ _.displayModel, (model) ->
switchPage Steam.ModelView _, model if _topic() is _modelTopic
switchPageView Steam.ModelView _, model if _topic() is _modelTopic

link$ _.displayScoring, (scoring) ->
switchPage Steam.ScoringView _, scoring if _topic() is _scoringTopic
switchPageView Steam.ScoringView _, scoring if _topic() is _scoringTopic

link$ _.displayNotification, (notification) ->
switchPage Steam.NotificationView _, notification if _topic() is _notificationTopic
switchPageView Steam.NotificationView _, notification if _topic() is _notificationTopic

link$ _.switchToFrames, switchToFrames

Expand All @@ -116,7 +126,7 @@ Steam.MainView = (_) ->

link$ _.switchToNotifications, switchToNotifications

link$ _.modelsSelected, -> switchModal _modelSelectionView
link$ _.modelsSelected, -> switchModalView _modelSelectionView

link$ _.modelsDeselected, -> _modalViews.remove _modelSelectionView

Expand All @@ -127,6 +137,7 @@ Steam.MainView = (_) ->
toggleTopics: toggleTopics
toggleHelp: toggleHelp
listViews: _listViews
selectionViews: _selectionViews
pageViews: _pageViews
modalViews: _modalViews
isListMasked: _isListMasked
Expand Down
7 changes: 4 additions & 3 deletions client/src/scripts/model-selection-view.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,16 @@ Steam.ModelSelectionView = (_) ->

scoreModels = ->
frameKey = _frameKey()
scores = map _selections(), (selection) ->
scorings = map _selections(), (selection) ->
frameKey: frameKey
model: selection.data
status: null
time: null
result: null
scoring = frameKey: frameKey, scores: scores, timestamp: Date.now()
timestamp: Date.now()

do cancel
_.switchToScoring type: 'scoring', scoring: scoring
_.switchToScoring type: 'scoring', scorings: scorings

cancel = ->
_selections.removeAll()
Expand Down
121 changes: 102 additions & 19 deletions client/src/scripts/scoring-list-view.coffee
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# TODO automatically batch scorings into colored groups
# HSL( (((i % 3) * n / 3) + (i / 3)) * 255.0 / n, 255, 128)

Steam.ScoringListView = (_) ->
_predicate = node$ type: 'all'
_items = do nodes$
Expand All @@ -8,12 +11,12 @@ Steam.ScoringListView = (_) ->

displayItem = (item) ->
if item
_.displayScoring item.data
_.displayScoring item
else
_.displayEmpty()

displayActiveItem = ->
displayItem find _items(), (item) -> item.isActive()
findActiveItem = ->
find _items(), (item) -> item.isActive()

activateAndDisplayItem = (item) ->
for other in _items()
Expand All @@ -24,47 +27,127 @@ Steam.ScoringListView = (_) ->

displayItem item

createItem = (scoring) ->
createScoringItem = (scoring) ->
#TODO replace with type checking
#TODO dispose isSelected properly
self =
data: scoring
type: 'scoring'
data:
input: scoring
output: null
title: scoring.frameKey
caption: describeCount scoring.scores.length, 'model'
caption: "#{scoring.model.model_algorithm} (#{scoring.model.response_column_name})"
cutline: new Date(scoring.timestamp).toString()
display: -> activateAndDisplayItem self
isActive: node$ no
isSelected: node$ no
state: node$ 'waiting'
isReady: node$ no
hasFailed: node$ no

apply$ _isLive, self.isSelected, (isLive, isSelected) ->
_.scoringSelectionChanged isSelected, _predicate(), scoring if isLive
self
_.scoringSelectionChanged isSelected, self if isLive

displayScorings = (scorings) ->
_items items = map scorings, createItem
activateAndDisplayItem head items
self

createComparisonItem = (comparison) ->
self =
type: 'comparison'
data: comparison
title: 'Comparison' #TODO needs a better caption
caption: describeCount comparison.scorings.length, 'scoring'
cutline: new Date(comparison.timestamp).toString()
display: -> activateAndDisplayItem self
isActive: node$ no
isSelected: node$ no
isReady: node$ yes
hasFailed: node$ no

apply$ _predicate, (predicate) ->
pastScorings = (_.getFromCache 'scoring') or _.putIntoCache 'scoring', []
if predicate.type is 'scoring'
pastScorings.unshift predicate.scoring
apply$ _isLive, self.isSelected, (isLive, isSelected) ->
_.scoringSelectionChanged isSelected, self if isLive

displayScorings pastScorings
self

runScoringJobs = (jobs, go) ->
queue = copy jobs
runNext = ->
if job = shift queue
job.run -> defer runNext
else
go()
defer runNext

createScoringJobs = (items) ->
map items, (item) ->
frameKey = item.data.input.frameKey
modelKey = item.data.input.model.key
run: (go) ->
item.state 'running'
_.requestScoringOnFrame frameKey, modelKey, (error, result) ->
item.state if error then 'error' else 'success'
item.isReady yes
if error
_.error 'Scoring failed', { frameKey: frameKey, modelKey: modelKey }, error
#item.time if error.response then error.response.time else 0
item.hasFailed yes
item.data.output = error
else
#TODO what does it mean to have > 1 metrics
#TODO put this in the comparison table
#item.time if result.metrics and result.metrics.length > 0 then (head result.metrics).duration_in_ms else 0
item.data.output = result

do go

loadScorings = (predicate) ->
console.assert isDefined predicate
#pastScorings = (_.getFromCache 'scoring') or _.putIntoCache 'scoring', []

switch predicate.type
when 'scoring'
items = map predicate.scorings, createScoringItem
_items.splice.apply _items, [0, 0].concat items
jobs = createScoringJobs items
runScoringJobs jobs, ->
activateAndDisplayItem head items
_.scoringsLoaded()
when 'comparison'
item = createComparisonItem
scorings: predicate.scorings
timestamp: predicate.timestamp
_items.unshift item
activateAndDisplayItem item

_predicate predicate
return

link$ _.loadScorings, (predicate) ->
if predicate
_predicate predicate
loadScorings predicate
else
displayActiveItem()
displayItem findActiveItem()

link$ _.deselectAllScorings, ->
deselectAllScorings = ->
#TODO ugly
_isLive no
for item in _items()
item.isSelected no
_isLive yes
_.scoringSelectionCleared()

deleteActiveScoring = () ->
_items.remove findActiveItem()
_.displayEmpty()

deleteScorings = (scorings) ->
deselectAllScorings()
_items.removeAll scorings
unless findActiveItem()
_.displayEmpty()

link$ _.deselectAllScorings, deselectAllScorings
link$ _.deleteScorings, deleteScorings
link$ _.deleteActiveScoring, deleteActiveScoring

items: _items
hasItems: _hasItems
Expand Down
57 changes: 57 additions & 0 deletions client/src/scripts/scoring-selection-view.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
Steam.ScoringSelectionView = (_) ->
_selections = do nodes$
_hasSelection = lift$ _selections, (selections) -> selections.length > 0
_caption = lift$ _selections, (selections) ->
"#{describeCount selections.length, 'item'} selected"
_canCompareScorings = lift$ _selections, (selections) ->
console.log selections

if selections.length < 2
return no

for selection in selections
if selection.type is 'comparison'
return no

yes

compareScorings = ->
_.loadScorings
type: 'comparison'
# Send a clone of selections because the selections gets cleared soon after.
scorings: clone _selections()
timestamp: Date.now()
_.deselectAllScorings()

deleteActiveScoring = ->
#TODO confirm dialog
_.deleteActiveScoring()

deleteScorings = ->
# Send a clone of selections because the selections gets cleared
# when deleted from the selection list.
#TODO confirm dialog
_.deleteScorings clone _selections()

clearSelections = ->
_.deselectAllScorings()

link$ _.scoringSelectionChanged, (isSelected, scoring) ->
if isSelected
_selections.push scoring
else
_selections.remove scoring

link$ _.scoringSelectionCleared, ->
_selections.removeAll()

caption: _caption
selections: _selections
hasSelection: _hasSelection
clearSelections: clearSelections
canCompareScorings: _canCompareScorings
compareScorings: compareScorings
deleteScorings: deleteScorings
deleteActiveScoring: deleteActiveScoring
template: 'scoring-selection-view'

Loading

0 comments on commit 38713f2

Please sign in to comment.