mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-29 02:25:37 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
74ab92012f
8 changed files with 159 additions and 109 deletions
|
@ -81,7 +81,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
|
|||
awaiting_levels_adventurer_prefix: "Nós adicionamos cinco níveis por semana."
|
||||
awaiting_levels_adventurer: "Regista-te como Aventureiro"
|
||||
awaiting_levels_adventurer_suffix: "para seres o primeiro a jogar níveis novos."
|
||||
# adjust_volume: "Adjust volume"
|
||||
adjust_volume: "Ajustar volume"
|
||||
choose_your_level: "Escolhe o Teu Nível" # The rest of this section is the old play view at /play-old and isn't very important.
|
||||
adventurer_prefix: "Podes saltar para um dos níveis abaixo ou discutir os níveis no "
|
||||
adventurer_forum: "fórum do Aventureiro"
|
||||
|
@ -480,7 +480,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
|
|||
versions:
|
||||
save_version_title: "Guardar Nova Versão"
|
||||
new_major_version: "Nova Versão Principal"
|
||||
# submitting_patch: "Submitting Patch..."
|
||||
submitting_patch: "A Submeter Atualização..."
|
||||
cla_prefix: "Para guardares as alterações, precisas de concordar com o nosso"
|
||||
cla_url: "CLA"
|
||||
cla_suffix: "."
|
||||
|
@ -636,8 +636,8 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
|
|||
level_tab_thangs_all: "Todos"
|
||||
level_tab_thangs_conditions: "Condições Iniciais"
|
||||
level_tab_thangs_add: "Adicionar Thangs"
|
||||
# add_components: "Add Components"
|
||||
# component_configs: "Component Configurations"
|
||||
add_components: "Adicionar Componentes"
|
||||
component_configs: "Configurações dos Componentes"
|
||||
config_thang: "Clica duas vezes para configurares uma thang"
|
||||
delete: "Eliminar"
|
||||
duplicate: "Duplicar"
|
||||
|
@ -885,7 +885,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
|
|||
leaderboard: "Tabela de Classificação"
|
||||
user_schema: "Esquema do Utilizador"
|
||||
user_profile: "Perfil do Utilizador"
|
||||
# patch: "Patch"
|
||||
patch: "Atualização"
|
||||
patches: "Atualizações"
|
||||
patched_model: "Documento Fonte"
|
||||
model: "Modelo"
|
||||
|
|
|
@ -25,4 +25,4 @@
|
|||
strong(data-i18n="loading_error.unknown") Unknown error.
|
||||
|
||||
button.btn.btn-xs.retry-loading-resource(data-i18n="common.retry", data-resource-index=resourceIndex) Retry
|
||||
button.btn.btn-xs.skip-loading-resource(data-i18n="common.skip", data-resource-index=resourceIndex) Skip
|
||||
button.btn.btn-xs.skip-loading-resource(data-i18n="play_level.skip", data-resource-index=resourceIndex) Skip
|
||||
|
|
37
app/templates/editor/campaign/campaign-analytics-modal.jade
Normal file
37
app/templates/editor/campaign/campaign-analytics-modal.jade
Normal file
|
@ -0,0 +1,37 @@
|
|||
extends /templates/core/modal-base
|
||||
|
||||
block modal-header-content
|
||||
h3 Campaign Analytics
|
||||
if campaignCompletions.startDay && campaignCompletions.endDay
|
||||
.input-group.input-group-sm
|
||||
input.form-control#input-startday(type='text', style='width:100px;', value=campaignCompletions.startDay)
|
||||
input.form-control#input-endday(type='text', style='width:100px;', value=campaignCompletions.endDay)
|
||||
button.btn.btn-default.btn-sm#reload-button(style='margin-left:10px;') Reload
|
||||
|
||||
block modal-body-content
|
||||
if campaignCompletions && campaignCompletions.levels
|
||||
table.table.table-bordered.table-condensed.table-hover(style='font-size:10pt')
|
||||
thead
|
||||
tr
|
||||
td Level
|
||||
td Started
|
||||
td Finished
|
||||
td Playtime (s)
|
||||
td Completion %
|
||||
tbody
|
||||
- for (var i = 0; i < campaignCompletions.levels.length; i++)
|
||||
tr
|
||||
td= campaignCompletions.levels[i].level
|
||||
td= campaignCompletions.levels[i].started
|
||||
td= campaignCompletions.levels[i].finished
|
||||
td= campaignCompletions.levels[i].averagePlaytime
|
||||
if campaignCompletions.top3.indexOf(campaignCompletions.levels[i].level) >= 0
|
||||
td(style='background-color:lightblue;')= campaignCompletions.levels[i].completionRate
|
||||
else if campaignCompletions.bottom3.indexOf(campaignCompletions.levels[i].level) >= 0
|
||||
td(style='background-color:pink;')= campaignCompletions.levels[i].completionRate
|
||||
else
|
||||
td= campaignCompletions.levels[i].completionRate
|
||||
else
|
||||
div Loading...
|
||||
|
||||
block modal-footer
|
|
@ -16,6 +16,9 @@ block header
|
|||
span.glyphicon-home.glyphicon
|
||||
|
||||
ul.nav.navbar-nav.navbar-right
|
||||
li#analytics-button
|
||||
a
|
||||
span.glyphicon-stats.glyphicon
|
||||
if me.isAdmin()
|
||||
li#save-button
|
||||
a
|
||||
|
@ -40,43 +43,5 @@ block outer_content
|
|||
#right-column
|
||||
#campaign-view
|
||||
#campaign-level-view.hidden
|
||||
if campaignCompletions
|
||||
button.btn.btn-default#analytics-button(title="Analytics", data-toggle="modal" data-target="#analytics-modal") Analytics
|
||||
.modal.fade#analytics-modal(tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true")
|
||||
.modal-dialog.modal-lg
|
||||
.modal-content
|
||||
.modal-header
|
||||
button.close(type="button", data-dismiss="modal", aria-label="Close")
|
||||
span(aria-hidden="true") ×
|
||||
h4.modal-title Analytics
|
||||
.modal-body
|
||||
if campaignCompletions.startDay
|
||||
if campaignCompletions.endDay
|
||||
div #{campaignCompletions.startDay} to #{campaignCompletions.endDay}
|
||||
else
|
||||
div #{campaignCompletions.startDay} to yesterday
|
||||
table.table.table-bordered.table-condensed.table-hover(style='font-size:10pt')
|
||||
thead
|
||||
tr
|
||||
td Level
|
||||
td Started
|
||||
td Finished
|
||||
td Playtime (s)
|
||||
td Completion %
|
||||
tbody
|
||||
- for (var i = 0; i < campaignCompletions.levels.length; i++)
|
||||
tr
|
||||
td= campaignCompletions.levels[i].level
|
||||
td= campaignCompletions.levels[i].started
|
||||
td= campaignCompletions.levels[i].finished
|
||||
td= campaignCompletions.levels[i].averagePlaytime
|
||||
if campaignCompletions.top3.indexOf(campaignCompletions.levels[i].level) >= 0
|
||||
td(style='background-color:lightblue;')= campaignCompletions.levels[i].completionRate
|
||||
else if campaignCompletions.bottom3.indexOf(campaignCompletions.levels[i].level) >= 0
|
||||
td(style='background-color:pink;')= campaignCompletions.levels[i].completionRate
|
||||
else
|
||||
td= campaignCompletions.levels[i].completionRate
|
||||
else
|
||||
button.btn.btn-default.disabled#analytics-button Analytics Loading...
|
||||
|
||||
block footer
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
extends /templates/core/modal-base
|
||||
|
||||
block modal-header-content
|
||||
h1 Add Components
|
||||
h1(data-i18n="editor.add_components") Add Components
|
||||
|
||||
block modal-body-content
|
||||
form
|
||||
|
|
101
app/views/editor/campaign/CampaignAnalyticsModal.coffee
Normal file
101
app/views/editor/campaign/CampaignAnalyticsModal.coffee
Normal file
|
@ -0,0 +1,101 @@
|
|||
template = require 'templates/editor/campaign/campaign-analytics-modal'
|
||||
utils = require 'core/utils'
|
||||
ModalView = require 'views/core/ModalView'
|
||||
|
||||
# TODO: jquery-ui datepicker doesn't work well in this view
|
||||
# TODO: the date format handling is confusing (yyyy-mm-dd <=> yyyymmdd)
|
||||
|
||||
module.exports = class CampaignAnalyticsModal extends ModalView
|
||||
id: 'campaign-analytics-modal'
|
||||
template: template
|
||||
plain: true
|
||||
|
||||
events:
|
||||
'click #reload-button': 'onClickReloadButton'
|
||||
|
||||
constructor: (options, @campaignHandle, @campaignCompletions) ->
|
||||
super options
|
||||
@getCampaignAnalytics() unless @campaignCompletions?.levels?
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.campaignCompletions = @campaignCompletions
|
||||
c
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
$("#input-startday").datepicker dateFormat: "yy-mm-dd"
|
||||
$("#input-endday").datepicker dateFormat: "yy-mm-dd"
|
||||
|
||||
onClickReloadButton: () =>
|
||||
startDay = $('#input-startday').val()
|
||||
endDay = $('#input-endday').val()
|
||||
delete @campaignCompletions.levels
|
||||
@render()
|
||||
@getCampaignAnalytics startDay, endDay
|
||||
|
||||
getCampaignAnalytics: (startDay, endDay) =>
|
||||
# Fetch campaign analytics, unless dates given
|
||||
|
||||
startDay = startDay.replace(/-/g, '') if startDay?
|
||||
endDay = endDay.replace(/-/g, '') if endDay?
|
||||
|
||||
startDay ?= utils.getUTCDay -14
|
||||
endDay ?= utils.getUTCDay -1
|
||||
|
||||
success = (data) =>
|
||||
return if @destroyed
|
||||
mapFn = (item) ->
|
||||
item.completionRate = (item.finished / item.started * 100).toFixed(2)
|
||||
item
|
||||
@campaignCompletions.levels = _.map data, mapFn, @
|
||||
sortedLevels = _.cloneDeep @campaignCompletions.levels
|
||||
sortedLevels = _.filter sortedLevels, ((a) -> a.finished >= 10), @
|
||||
sortedLevels.sort (a, b) -> b.completionRate - a.completionRate
|
||||
@campaignCompletions.top3 = _.pluck sortedLevels[0..2], 'level'
|
||||
sortedLevels.sort (a, b) -> a.completionRate - b.completionRate
|
||||
@campaignCompletions.bottom3 = _.pluck sortedLevels[0..2], 'level'
|
||||
@campaignCompletions.startDay = "#{startDay[0..3]}-#{startDay[4..5]}-#{startDay[6..7]}"
|
||||
@campaignCompletions.endDay = "#{endDay[0..3]}-#{endDay[4..5]}-#{endDay[6..7]}"
|
||||
@getCampaignAveragePlaytimes startDay, endDay
|
||||
|
||||
# TODO: Why do we need this url dash?
|
||||
request = @supermodel.addRequestResource 'campaign_completions', {
|
||||
url: '/db/analytics_perday/-/campaign_completions'
|
||||
data: {startDay: startDay, endDay: endDay, slug: @campaignHandle}
|
||||
method: 'POST'
|
||||
success: success
|
||||
}, 0
|
||||
request.load()
|
||||
|
||||
getCampaignAveragePlaytimes: (startDay, endDay) =>
|
||||
# Fetch level average playtimes
|
||||
success = (data) =>
|
||||
return if @destroyed
|
||||
levelAverages = {}
|
||||
for item in data
|
||||
levelAverages[item.level] ?= []
|
||||
levelAverages[item.level].push item.average
|
||||
for level in @campaignCompletions.levels
|
||||
if levelAverages[level.level]
|
||||
if levelAverages[level.level].length > 0
|
||||
total = _.reduce levelAverages[level.level], ((sum, num) -> sum + num)
|
||||
level.averagePlaytime = (total / levelAverages[level.level].length).toFixed(2)
|
||||
else
|
||||
level.averagePlaytime = 0.0
|
||||
@render()
|
||||
|
||||
startDay ?= utils.getUTCDay -14
|
||||
startDay = "#{startDay[0..3]}-#{startDay[4..5]}-#{startDay[6..7]}"
|
||||
endDay ?= utils.getUTCDay -1
|
||||
endDay = "#{endDay[0..3]}-#{endDay[4..5]}-#{endDay[6..7]}"
|
||||
|
||||
levelSlugs = _.pluck @campaignCompletions.levels, 'level'
|
||||
|
||||
request = @supermodel.addRequestResource 'playtime_averages', {
|
||||
url: '/db/level/-/playtime_averages'
|
||||
data: {startDay: startDay, endDay: endDay, slugs: levelSlugs}
|
||||
method: 'POST'
|
||||
success: success
|
||||
}, 0
|
||||
request.load()
|
|
@ -7,9 +7,10 @@ CampaignView = require 'views/play/CampaignView'
|
|||
CocoCollection = require 'collections/CocoCollection'
|
||||
treemaExt = require 'core/treema-ext'
|
||||
utils = require 'core/utils'
|
||||
SaveCampaignModal = require './SaveCampaignModal'
|
||||
RelatedAchievementsCollection = require 'collections/RelatedAchievementsCollection'
|
||||
CampaignAnalyticsModal = require './CampaignAnalyticsModal'
|
||||
CampaignLevelView = require './CampaignLevelView'
|
||||
SaveCampaignModal = require './SaveCampaignModal'
|
||||
|
||||
achievementProject = ['related', 'rewards', 'name', 'slug']
|
||||
thangTypeProject = ['name', 'original']
|
||||
|
@ -20,6 +21,7 @@ module.exports = class CampaignEditorView extends RootView
|
|||
className: 'editor'
|
||||
|
||||
events:
|
||||
'click #analytics-button': 'onClickAnalyticsButton'
|
||||
'click #save-button': 'onClickSaveButton'
|
||||
|
||||
constructor: (options, @campaignHandle) ->
|
||||
|
@ -27,6 +29,9 @@ module.exports = class CampaignEditorView extends RootView
|
|||
@campaign = new Campaign({_id:@campaignHandle})
|
||||
@supermodel.loadModel(@campaign, 'campaign')
|
||||
|
||||
# Save reference to data used by anlytics modal so it persists across modal open/closes.
|
||||
@campaignAnalytics = {}
|
||||
|
||||
@levels = new CocoCollection([], {
|
||||
model: Level
|
||||
url: "/db/campaign/#{@campaignHandle}/levels"
|
||||
|
@ -47,8 +52,6 @@ module.exports = class CampaignEditorView extends RootView
|
|||
@listenToOnce @levels, 'sync', @onFundamentalLoaded
|
||||
@listenToOnce @achievements, 'sync', @onFundamentalLoaded
|
||||
|
||||
_.delay @getCampaignAnalytics, 500
|
||||
|
||||
loadThangTypeNames: ->
|
||||
# Load the names of the ThangTypes that this level's Treema nodes might want to display.
|
||||
originals = []
|
||||
|
@ -132,9 +135,11 @@ module.exports = class CampaignEditorView extends RootView
|
|||
getRenderData: ->
|
||||
c = super()
|
||||
c.campaign = @campaign
|
||||
c.campaignCompletions = @campaignCompletions
|
||||
c
|
||||
|
||||
onClickAnalyticsButton: ->
|
||||
@openModalView new CampaignAnalyticsModal {}, @campaignHandle, @campaignAnalytics
|
||||
|
||||
onClickSaveButton: ->
|
||||
@toSave.set @toSave.filter (m) -> m.hasLocalChanges()
|
||||
@openModalView new SaveCampaignModal({}, @toSave)
|
||||
|
@ -240,65 +245,6 @@ module.exports = class CampaignEditorView extends RootView
|
|||
if achievement.hasLocalChanges()
|
||||
@toSave.add achievement
|
||||
|
||||
getCampaignAnalytics: =>
|
||||
# Fetch last 14 days of campaign analytics
|
||||
|
||||
startDay = utils.getUTCDay -14
|
||||
endDay = utils.getUTCDay -1
|
||||
|
||||
success = (data) =>
|
||||
return if @destroyed
|
||||
mapFn = (item) ->
|
||||
item.completionRate = (item.finished / item.started * 100).toFixed(2)
|
||||
item
|
||||
@campaignCompletions = levels: _.map data, mapFn, @
|
||||
sortedLevels = _.cloneDeep @campaignCompletions.levels
|
||||
sortedLevels = _.filter sortedLevels, ((a) -> a.completionRate > 1.0), @
|
||||
sortedLevels.sort (a, b) -> b.completionRate - a.completionRate
|
||||
@campaignCompletions.top3 = _.pluck sortedLevels[0..2], 'level'
|
||||
sortedLevels.sort (a, b) -> a.completionRate - b.completionRate
|
||||
@campaignCompletions.bottom3 = _.pluck sortedLevels[0..2], 'level'
|
||||
@campaignCompletions.startDay = "#{startDay[0..3]}-#{startDay[4..5]}-#{startDay[6..7]}"
|
||||
@campaignCompletions.endDay = "#{endDay[0..3]}-#{endDay[4..5]}-#{endDay[6..7]}"
|
||||
@getCampaignAveragePlaytimes()
|
||||
|
||||
# TODO: Why do we need this url dash?
|
||||
request = @supermodel.addRequestResource 'campaign_completions', {
|
||||
url: '/db/analytics_perday/-/campaign_completions'
|
||||
data: {startDay: startDay, slug: @campaignHandle}
|
||||
method: 'POST'
|
||||
success: success
|
||||
}, 0
|
||||
request.load()
|
||||
|
||||
getCampaignAveragePlaytimes: =>
|
||||
# Fetch last 14 days of level average playtimes
|
||||
success = (data) =>
|
||||
return if @destroyed
|
||||
levelAverages = {}
|
||||
for item in data
|
||||
levelAverages[item.level] ?= []
|
||||
levelAverages[item.level].push item.average
|
||||
for level in @campaignCompletions.levels
|
||||
if levelAverages[level.level]
|
||||
if levelAverages[level.level].length > 0
|
||||
total = _.reduce levelAverages[level.level], ((sum, num) -> sum + num)
|
||||
level.averagePlaytime = (total / levelAverages[level.level].length).toFixed(2)
|
||||
else
|
||||
level.averagePlaytime = 0.0
|
||||
@render()
|
||||
|
||||
levelSlugs = _.pluck @campaignCompletions.levels, 'level'
|
||||
startDay = utils.getUTCDay -14
|
||||
startDay = "#{startDay[0..3]}-#{startDay[4..5]}-#{startDay[6..7]}"
|
||||
request = @supermodel.addRequestResource 'playtime_averages', {
|
||||
url: '/db/level/-/playtime_averages'
|
||||
data: {startDay: startDay, slugs: levelSlugs}
|
||||
method: 'POST'
|
||||
success: success
|
||||
}, 0
|
||||
request.load()
|
||||
|
||||
|
||||
class LevelsNode extends TreemaObjectNode
|
||||
valueClass: 'treema-levels'
|
||||
|
|
|
@ -151,7 +151,8 @@ module.exports = class Spell
|
|||
writable = @permissions.readwrite.length > 0
|
||||
skipProtectAPI = @skipProtectAPI or not writable
|
||||
problemContext = @createProblemContext thang
|
||||
aetherOptions = createAetherOptions functionName: @name, codeLanguage: @language, functionParameters: @parameters, skipProtectAPI: skipProtectAPI, includeFlow: @levelType in ['hero', 'hero-ladder', 'hero-coop'], problemContext: problemContext
|
||||
includeFlow = (@levelType in ['hero', 'hero-ladder', 'hero-coop']) and not skipProtectAPI
|
||||
aetherOptions = createAetherOptions functionName: @name, codeLanguage: @language, functionParameters: @parameters, skipProtectAPI: skipProtectAPI, includeFlow: includeFlow, problemContext: problemContext
|
||||
aether = new Aether aetherOptions
|
||||
if @worker
|
||||
workerMessage =
|
||||
|
|
Loading…
Reference in a new issue