diff --git a/.taskcluster.yml b/.taskcluster.yml
index 6bc48f708..b01a2f794 100644
--- a/.taskcluster.yml
+++ b/.taskcluster.yml
@@ -32,6 +32,17 @@ tasks:
else: 'dev'
else: 'dev'
+ backend_url:
+ $if: 'tasks_for == "github-push"'
+ then:
+ $if: 'event.ref == "refs/heads/testing"'
+ then: 'https://api.code-review.testing.moz.tools'
+ else: 'https://api.code-review.moz.tools'
+ else:
+ $if: 'tasks_for == "github-pull-request"'
+ then: 'https://api.code-review.testing.moz.tools'
+ else: 'https://api.code-review.moz.tools'
+
taskboot_image: "mozilla/taskboot:0.1.10"
pip_install: "pip install --disable-pip-version-check --no-cache-dir --quiet"
@@ -129,6 +140,8 @@ tasks:
payload:
maxRunTime: 3600
image: node:11-alpine
+ env:
+ BACKEND_URL: "${backend_url}"
command:
- sh
- -lxce
diff --git a/frontend/.neutrinorc.js b/frontend/.neutrinorc.js
index 0c6bf4aca..5d104d8a9 100644
--- a/frontend/.neutrinorc.js
+++ b/frontend/.neutrinorc.js
@@ -2,6 +2,7 @@ fs = require('fs');
const envs = {
CONFIG: process.env.CONFIG || 'staging',
+ BACKEND_URL: process.env.BACKEND_URL || 'http://localhost:8000',
};
const PORT = process.env.PORT || 8010;
// HTTPS can be disabled by setting HTTPS_DISABLED environment variable to
@@ -26,7 +27,7 @@ module.exports = {
'@neutrinojs/vue',
{
html: {
- title: 'Mozilla Static Analysis'
+ title: 'Mozilla Code Review Bot'
},
devServer: {
port: PORT,
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 7025ac200..c3f37b959 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "code-review-frontend",
- "version": "1.0.5",
+ "version": "1.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index f5ac17eb4..f61a5374d 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -1,24 +1,9 @@
+
+
+
+
+
+
+
+
+
Sorry, no diffs are available for your search terms !
+
+
+
+
+
+
diff --git a/frontend/src/Issues.vue b/frontend/src/Issues.vue
new file mode 100644
index 000000000..0da38753e
--- /dev/null
+++ b/frontend/src/Issues.vue
@@ -0,0 +1,197 @@
+
+
+
+
+
Diff {{ $route.params.diffId }}
+
+
Loading diff...
+
No diff, so no issues !
+
Failure
+
+
+
+
+
+
+
+ | Hash |
+ |
+ |
+ Lines |
+ |
+ Check |
+ Level |
+ Message |
+
+
+
+
+
+ | {{ issue.hash.substring(0, 12) }} |
+
+ {{ issue.analyzer }}
+ |
+ {{ issue.path }} |
+ {{ issue.line }} → {{ issue.line - 1 + issue.nb_lines }} |
+
+
+ |
+
+
+ {{ issue.check }}
+ |
+
+ Error
+ Warning
+ {{ issue.level }}
+ |
+
+ {{ issue.message }}
+
+
+ {{ issue.body }}
+
+ |
+
+
+
+
+
No issues !
+
+
+
+
diff --git a/frontend/src/Revision.vue b/frontend/src/Revision.vue
new file mode 100644
index 000000000..4a7981fa9
--- /dev/null
+++ b/frontend/src/Revision.vue
@@ -0,0 +1,102 @@
+
+
+
+
+ Revision D{{ $route.params.revisionId }}
+
+ Loading...
+
+
{{ revision.title }}
+
+ On {{ revision.repository }} - View on Phabricator
+
+ - View Bug {{ revision.bugzilla_id }}
+
+
+
+
+
+
+
+
Error
+ {{ state }}
+
+
+
+
+
diff --git a/frontend/src/Stats.vue b/frontend/src/Stats.vue
index 388a02bd0..95025f655 100644
--- a/frontend/src/Stats.vue
+++ b/frontend/src/Stats.vue
@@ -9,30 +9,30 @@ export default {
],
data () {
return {
- sort: 'published'
+ sort: 'detected'
}
},
components: { Progress },
mounted () {
- this.$store.dispatch('calc_stats')
+ this.$store.dispatch('load_stats')
},
computed: {
checks () {
- if (!this.stats || !this.stats.loaded) {
+ if (!this.stats) {
return null
}
let sortStr = (x, y) => x.toLowerCase().localeCompare(y.toLowerCase())
var sorts = {
+ 'repository': (x, y) => sortStr(x.repository, y.repository),
'analyzer': (x, y) => sortStr(x.analyzer, y.analyzer) || sortStr(x.check, y.check),
'check': (x, y) => sortStr(x.check, y.check),
'detected': (x, y) => y.total - x.total,
'published': (x, y) => y.publishable - x.publishable
}
- // Apply local sort to the checks from store
- var checks = Object.values(this.stats.checks)
- checks.sort(sorts[this.sort])
- return checks
+ // Apply local sort to the stats from store
+ this.stats.sort(sorts[this.sort])
+ return this.stats
}
},
methods: {
@@ -51,6 +51,9 @@ export default {
+ |
+ Repository
+ |
Analyzer
|
@@ -67,11 +70,9 @@ export default {
+ | {{ check.repository }} |
{{ check.analyzer }} |
-
- {{ check.check }}
- {{ check.message }}
- |
+ {{ check.check }} |
{{ check.total }} |
{{ check.publishable }}
diff --git a/frontend/src/Task.vue b/frontend/src/Task.vue
deleted file mode 100644
index b9b49ad1e..000000000
--- a/frontend/src/Task.vue
+++ /dev/null
@@ -1,223 +0,0 @@
-
-
-
-
-
-
- Loading report...
- No report, so no issues !
- Failure
-
-
-
-
-
-
-
- |
- |
- Lines |
- |
- Check |
- Level |
- Message |
-
-
-
-
-
-
- {{ issue.linter }} by Mozlint
- {{ issue.analyzer }}
- |
- {{ issue.path }} |
- {{ issue.line }} → {{ issue.line - 1 + issue.nb_lines }} |
-
-
-
- |
-
-
- {{ issue.rule }}
- {{ issue.check }}
- Style issue
- {{ issue.bug_type }}
- {{ issue.bug_type }}
{{ issue.kind }}
- |
-
- Error
- Warning
- |
-
- {{ issue.message }}
- {{ issue.message }}
-
-
- {{ issue.body }}
-
-
-
- Replace
- {{ issue.old_lines }}
- by these:
- {{ issue.new_lines }}
-
-
- Insert these lines
- {{ issue.new_lines }}
-
-
- Delete these lines
- {{ issue.old_lines }}
-
- |
-
-
-
-
- No issues !
-
-
-
-
diff --git a/frontend/src/Tasks.vue b/frontend/src/Tasks.vue
index f9f7979c3..c491e6dc7 100644
--- a/frontend/src/Tasks.vue
+++ b/frontend/src/Tasks.vue
@@ -5,29 +5,13 @@ import Choice from './Choice.vue'
export default {
mounted () {
- // Load new tasks at startup
- this.load_tasks()
- },
- watch: {
- '$route' (to, from, next) {
- // Load new tasks when route change
- if (to.path !== from.path) {
- this.load_tasks()
- }
- }
+ this.load_tasks('production')
},
methods: {
- load_tasks () {
- var payload = {}
-
- // Reset state
+ load_tasks (channel) {
+ this.$set(this, 'channel', channel)
this.$store.commit('reset')
-
- // Load a specific revision only
- if (this.$route.params.revision) {
- payload['revision'] = this.$route.params.revision
- }
- this.$store.dispatch('load_index', payload)
+ this.$store.dispatch('load_index', { channel })
}
},
components: {
@@ -35,6 +19,7 @@ export default {
},
data: function () {
return {
+ channel: 'production',
filters: {
state: null,
issues: null,
@@ -73,7 +58,7 @@ export default {
// Filter by states
if (this.filters.state !== null) {
- tasks = _.filter(tasks, t => t.state_full === this.filters.state.key)
+ tasks = _.filter(tasks, t => t.data.state === this.filters.state.key)
}
// Filter by issues
@@ -89,22 +74,37 @@ export default {
})
}
- return tasks
+ // Sort by indexation date
+ return tasks.sort((x, y) => {
+ return new Date(y.data.indexed) - new Date(x.data.indexed)
+ })
},
tasks_total () {
return this.$store.state.tasks ? this.$store.state.tasks.length : 0
},
states () {
- return this.$store.state.states
+ let currentTasks = this.$store.state.tasks
+ const states = currentTasks.reduce((states, task) => {
+ if (states[task.data.state] === undefined) {
+ states[task.data.state] = 0
+ }
+ states[task.data.state] += 1
+ return states
+ }, {})
+
+ // Order states by their nb, and calc percents
+ return Object.keys(states).map(state => {
+ let nb = states[state]
+ return {
+ 'key': state,
+ 'name': state.startsWith('error.') ? 'error: ' + state.substring(6) : state,
+ 'nb': nb,
+ 'percent': currentTasks && currentTasks.length > 0 ? Math.round(nb * 100 / currentTasks.length) : 0
+ }
+ }).sort((x, y) => { return y.nb - x.nb })
},
repositories () {
- // Convert repositories set to an array
- return [...this.$store.state.repositories].map(url => {
- if (url.startsWith('https://hg.mozilla.org/')) {
- return url.substring(23)
- }
- return url
- })
+ return []
}
}
}
@@ -112,6 +112,10 @@ export default {
+
+
+
+
@@ -158,7 +162,7 @@ export default {
{{ task.data.diff_phid}} - diff {{ task.data.diff_id || 'unknown' }}
- {{ task.data.phid}} - rev {{ task.data.id }}
+ {{ task.data.phid}} - rev {{ task.data.id }}
|
@@ -198,7 +202,7 @@ export default {
Phabricator
Bugzilla
Try Tasks
- Issues
+ Issues
diff --git a/frontend/src/index.js b/frontend/src/index.js
index 3efb956fa..325213eb5 100644
--- a/frontend/src/index.js
+++ b/frontend/src/index.js
@@ -8,8 +8,5 @@ export default new Vue({
store,
router,
el: '#root',
- render: (h) => h(App),
- beforeCreate () {
- this.$store.commit('load_preferences')
- }
+ render: (h) => h(App)
})
diff --git a/frontend/src/mixins.js b/frontend/src/mixins.js
index 4d097de7e..2fa75a983 100644
--- a/frontend/src/mixins.js
+++ b/frontend/src/mixins.js
@@ -1,14 +1,30 @@
export default {
+ query: {
+ methods: {
+ update_query (name, value) {
+ console.log('update query', name, value)
+ var query = Object.assign({}, this.$route.query)
+ if (value !== null && value !== '') {
+ query[name] = value
+ } else if (name in query) {
+ delete query[name]
+ }
+ if (this.$router) {
+ this.$router.push({ 'query': query })
+ }
+ }
+ }
+ },
stats: {
computed: {
stats () {
return this.$store.state.stats
},
progress () {
- if (!this.stats.ids || !this.stats.loaded) {
- return 0.0
+ if (!this.$store.state.total_stats) {
+ return 0
}
- return 100 * this.stats.loaded / this.stats.ids.length
+ return 100 * this.stats.length / this.$store.state.total_stats
}
}
},
@@ -16,14 +32,21 @@ export default {
filters: {
// Display time since elapsed in a human format
since (datetime) {
- var dspStep = (t, name) => (Math.round(t) + ' ' + name + (Math.round(t) > 1 ? 's' : ''))
+ var dspStep = (t, name) => {
+ let x = Math.round(t)
+ if (x === 0) {
+ return ''
+ }
+ return x + ' ' + name + (x > 1 ? 's' : '')
+ }
let diff = (new Date() - new Date(datetime)) / 1000
let steps = [
[60, 'second'],
[60, 'minute'],
[24, 'hour'],
- [30, 'day']
+ [30, 'day'],
+ [12, 'month']
]
var prev = ''
for (let [t, name] of steps) {
diff --git a/frontend/src/routes.js b/frontend/src/routes.js
index dafd50c49..0a2ce0e6a 100644
--- a/frontend/src/routes.js
+++ b/frontend/src/routes.js
@@ -1,7 +1,9 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
+import Diffs from './Diffs.vue'
import Tasks from './Tasks.vue'
-import Task from './Task.vue'
+import Revision from './Revision.vue'
+import Issues from './Issues.vue'
import Stats from './Stats.vue'
import Check from './Check.vue'
@@ -11,18 +13,23 @@ export default new VueRouter({
routes: [
{
path: '/',
+ name: 'diffs',
+ component: Diffs
+ },
+ {
+ path: '/tasks',
name: 'tasks',
component: Tasks
},
{
- path: '/rev/:revision',
+ path: '/D:revisionId',
name: 'revision',
- component: Tasks
+ component: Revision
},
{
- path: '/task/:taskId',
- name: 'task',
- component: Task
+ path: '/diff/:diffId',
+ name: 'diff',
+ component: Issues
},
{
path: '/stats',
diff --git a/frontend/src/store.js b/frontend/src/store.js
index 3ef01437a..98faae9ee 100644
--- a/frontend/src/store.js
+++ b/frontend/src/store.js
@@ -1,219 +1,184 @@
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
-import router from './routes'
Vue.use(Vuex)
-const PREFERENCES_KEY = 'mozilla-sa-dashboard'
-const TASKCLUSTER_ROOT_URL = 'https://firefox-ci-tc.services.mozilla.com/'
-const TASKS_SLICE = 10
-const FINAL_STATES = ['done', 'error']
-
-// Must stay in sync with src/staticanalysis/bot/default.nix maxRunTime & deadline parameters
-// This is currently set to 2 hours in ms
-const MAX_TTL = 2 * 3600 * 1000
+const TASKCLUSTER_DIFF_INDEX = 'https://index.taskcluster.net/v1/task/project.relman.production.code-review.phabricator.diff.'
export default new Vuex.Store({
state: {
- channel: 'production',
+ backend_url: process.env.BACKEND_URL,
tasks: [],
- indexes: [],
- stats: {
- loaded: 0,
- errors: 0,
- ids: [],
- checks: {},
- start_date: new Date()
- },
+ diffs: [],
+ stats: null,
+ total_stats: 0, // Used to track download progress
states: null,
- repositories: new Set(),
- report: null
+ repositories: null,
+ diff: null,
+ issues: {},
+ revision: null
},
mutations: {
- load_preferences (state) {
- // Load prefs from local storage
- let rawPrefs = localStorage.getItem(PREFERENCES_KEY)
- if (rawPrefs) {
- let prefs = JSON.parse(rawPrefs)
- if (prefs.channel) {
- state.channel = prefs.channel
- }
- }
- },
- save_preferences (state) {
- // Save channel to preferences
- localStorage.setItem(PREFERENCES_KEY, JSON.stringify({
- channel: state.channel
- }))
- },
- use_channel (state, channel) {
- state.channel = channel
- this.commit('reset')
- this.commit('save_preferences')
- },
reset (state) {
state.tasks = []
- state.indexes = []
- state.stats = {
- loaded: 0,
- errors: 0,
- ids: [],
- checks: {},
- start_date: new Date()
- }
+ state.diffs = []
+ state.diff = null
},
- use_tasks (state, payload) {
- var now = new Date()
- // Save url
- state.indexes.push(payload.url)
+ reset_stats (state) {
+ state.stats = []
+ state.total_stats = 0
+ },
- // Filter tasks without extra data
- let currentTasks = state.tasks.concat(
- payload.tasks.filter(task => task.data.indexed !== undefined)
- )
+ use_tasks (state, tasks) {
+ state.tasks = state.tasks.concat(tasks['tasks'])
+ },
- currentTasks.map(task => {
- // Add a descriptive state key name to tasks
- task.state_full = task.data.state
- if (task.state_full === 'error' && task.data.error_code) {
- task.state_full += '.' + task.data.error_code
- }
+ use_diffs (state, diffs) {
+ // Simply store diffs & their current pagination
+ state.diffs = diffs
+ },
- // Detect and update invalid state when a task got killed by Taskcluster
- let date = new Date(task.data.indexed)
- if (now - date > MAX_TTL && FINAL_STATES.indexOf(task.data.state) === -1) {
- task.data.state = 'killed'
- task.state_full = 'killed'
- }
+ use_repositories (state, repositories) {
+ // Simply store repositories directly
+ state.repositories = repositories
+ },
- // Use full urls for old style slugs
- if (task.data.repository === 'mozilla-central') {
- task.data.repository = 'https://hg.mozilla.org/mozilla-central'
- } else if (task.data.repository === 'nss') {
- task.data.repository = 'https://hg.mozilla.org/projects/nss'
- }
+ use_revision (state, payload) {
+ state.revision = Object.assign(payload.revision, { 'diffs': payload.diffs })
+ },
- return task
- })
+ // Store a new diff to display
+ use_diff (state, diff) {
+ state.diff = diff
+ if (state.diff !== null) {
+ state.diff.issues = []
+ }
+ },
- // Sort by indexation date
- currentTasks.sort((x, y) => {
- return new Date(y.data.indexed) - new Date(x.data.indexed)
+ // Add issues to a diff
+ add_issues (state, payload) {
+ let update = {}
+ let issues = state.issues[payload.diffId] || []
+ update[payload.diffId] = issues.concat(payload.issues)
+ state.issues = Object.assign({}, state.issues, update)
+ },
+
+ // Add stats to the store
+ add_stats (state, data) {
+ state.stats = state.stats.concat(data.results)
+ state.total_stats = data.count
+ }
+ },
+ actions: {
+ // Load Phabricator diffs from our backend
+ // Load a single page at once, providing pagination state
+ load_diffs (state, payload) {
+ let url = payload.url || this.state.backend_url + '/v1/diff/'
+
+ let params = payload.query || {}
+ return axios.get(url, { params: params }).then(resp => {
+ state.commit('use_diffs', resp.data)
})
+ },
- // Crunch stats about status
- let states = {}
- states = currentTasks.reduce((states, task) => {
- if (states[task.state_full] === undefined) {
- states[task.state_full] = 0
- }
- states[task.state_full] += 1
- return states
- }, states)
+ // Load a specific diff and its issues
+ load_diff (state, diffId) {
+ let url = this.state.backend_url + '/v1/diff/' + diffId
+ state.commit('use_diff', null)
+ return axios.get(url).then(resp => {
+ state.commit('use_diff', resp.data)
- // Save tasks
- state.tasks = currentTasks
+ // Load all issues in that diff
+ state.dispatch('load_issues', {
+ diffId: diffId,
+ url: resp.data.issues_url
+ })
+ }).catch(err => {
+ state.commit('use_diff', err)
+ })
+ },
- // Order states by their nb, and calc percents
- state.states = Object.keys(states).map(state => {
- let nb = states[state]
- return {
- 'key': state,
- 'name': state.startsWith('error.') ? 'error: ' + state.substring(6) : state,
- 'nb': nb,
- 'percent': currentTasks && currentTasks.length > 0 ? Math.round(nb * 100 / currentTasks.length) : 0
- }
- }).sort((x, y) => { return y.nb - x.nb })
+ load_issues (state, payload) {
+ if (payload.url === null) {
+ return
+ }
- // Update repositories reference
- state.repositories = new Set(state.tasks.map(t => t.data.repository).filter(x => x))
+ axios.get(payload.url).then(resp => {
+ // Store new issues
+ state.commit('add_issues', {
+ diffId: payload.diffId,
+ issues: resp.data.results
+ })
- // List all active tasks Ids for stats calculations
- state.stats.ids = state.stats.ids.concat(
- payload.tasks
- .filter((task) => task.data.state === 'done' && task.data.issues > 0)
- .map(t => t.taskId)
- )
+ // Load next issues
+ payload.url = resp.data.next
+ state.dispatch('load_issues', payload)
+ })
},
- use_report (state, report) {
- if (report === null) {
+
+ load_stats (state, url) {
+ if (url === null) {
return
+ } else if (url === undefined) {
+ state.commit('reset_stats')
+ url = this.state.backend_url + '/v1/check/stats/'
}
- // Save raw report for issues listing
- state.report = report
+ axios.get(url).then(resp => {
+ // Store new stats
+ state.commit('add_stats', resp.data)
- if (report.response && report.response.status !== 200) {
- // Manage errors
- state.stats.errors += 1
- return
- }
+ // Load next stats
+ state.dispatch('load_stats', resp.data.next)
+ })
+ },
- if (state.stats !== null && report.issues) {
- // Calc stats for this report
- state.stats.checks = report.issues.reduce((stats, issue) => {
- let key = issue.analyzer + '.' + issue.check
- if (stats[key] === undefined) {
- stats[key] = {
- analyzer: issue.analyzer,
- key: key,
- message: issue.message,
- check: issue.check,
- publishable: 0,
- issues: [],
- total: 0
- }
- }
- stats[key].publishable += issue.publishable ? 1 : 0
- stats[key].total++
+ load_repositories (state, payload) {
+ let url = this.state.backend_url + '/v1/repository/'
- // Save publishable issues for Check component
- // and link report data to the issue
- if (issue.publishable) {
- let extras = {
- revision: report.revision,
- taskId: report.taskId
- }
- stats[key].issues.push(Object.assign(extras, issue))
- }
- return stats
- }, state.stats.checks)
+ return axios.get(url).then(resp => {
+ // Assume we only have one page here
+ state.commit('use_repositories', resp.data.results)
+ })
+ },
- // Save start date
- state.stats.start_date = new Date(Math.min(new Date(report.time * 1000.0), state.stats.start_date))
+ // Retrieve diff data stored in Taskcluster index
+ // Do not persist that data in our store
+ load_taskcluster_diff (state, payload) {
+ let url = TASKCLUSTER_DIFF_INDEX + payload.id
+ return axios.get(url)
+ },
- // Mark new report loaded
- state.stats.loaded += 1
- }
- }
- },
- actions: {
- // Switch data channel to use
- switch_channel (state, channel) {
- state.commit('use_channel', channel)
- state.dispatch('load_index')
- router.push({ name: 'tasks' })
+ // Load a specific revision and its diffs
+ load_revision (state, payload) {
+ return Promise.all([
+ axios.get(this.state.backend_url + '/v1/revision/' + payload.id),
+ axios.get(this.state.backend_url + '/v1/revision/' + payload.id + '/diffs/')
+ ]).then(([respRevision, respDiffs]) => {
+ // Store revision & diffs data
+ state.commit('use_revision', {
+ revision: respRevision.data,
+ diffs: respDiffs.data.results
+ })
+
+ // Start loading issues for each diff
+ for (let diff of respDiffs.data.results) {
+ state.dispatch('load_issues', {
+ diffId: diff.id,
+ url: diff.issues_url
+ })
+ }
+ })
},
// Load Phabricator indexed tasks summary from Taskcluster
load_index (state, payload) {
- let url = TASKCLUSTER_ROOT_URL + 'api/index/v1/tasks/project.relman.' + this.state.channel + '.code-review.phabricator.'
- if (payload && payload.revision) {
- // Remove potential leading 'D' from phabricator revision
- url += !Number.isInteger(payload.revision) && payload.revision.startsWith('D') ? payload.revision.substring(1) : payload.revision
- } else {
- url += 'diff'
- }
-
- url += '?limit=200'
+ let channel = payload.channel || 'production'
+ let url = `https://firefox-ci-tc.services.mozilla.com/api/index/v1/tasks/project.relman.${channel}.code-review.phabricator.diff?limit=200`
if (payload && payload.continuationToken) {
url += '&continuationToken=' + payload.continuationToken
}
- if (state.state.indexes.includes(url)) {
- console.debug('Already loaded', url)
- return
- }
return axios.get(url).then(resp => {
state.commit('use_tasks', {
tasks: resp.data.tasks,
@@ -222,51 +187,12 @@ export default new Vuex.Store({
// Continue loading available tasks
if (resp.data.continuationToken) {
- state.dispatch('load_index', { continuationToken: resp.data.continuationToken })
+ state.dispatch('load_index', {
+ channel,
+ continuationToken: resp.data.continuationToken
+ })
}
})
- },
-
- // Load the report for a given task
- load_report (state, taskId) {
- let url = TASKCLUSTER_ROOT_URL + 'api/queue/v1/task/' + taskId + '/artifacts/public/results/report.json'
- state.commit('use_report', null)
- return axios.get(url).then(resp => {
- state.commit('use_report', Object.assign({ taskId }, resp.data))
- }).catch(err => {
- state.commit('use_report', err)
- })
- },
-
- // Load multiple reports for stats crunching
- calc_stats (state, tasksId) {
- // Avoid multiple loads
- if (state.state.stats.loaded > 0) {
- return
- }
-
- // Load all indexes to get task ids
- // and avoid reloading tasks
- var indexes = state.state.tasks.length > 0 ? Promise.resolve(true) : state.dispatch('load_index')
- indexes.then(() => {
- console.log('Start analysis')
-
- // Start processing by batches
- state.dispatch('load_report_batch', 0)
- })
- },
- load_report_batch (state, step) {
- if (step * TASKS_SLICE > state.state.stats.ids.length) {
- return
- }
-
- // Slice full loading in smaller batches to avoid using too many resources
- var slice = state.state.stats.ids.slice(step * TASKS_SLICE, (step + 1) * TASKS_SLICE)
- var batch = Promise.all(
- slice.map(taskId => state.dispatch('load_report', taskId))
- )
- batch.then(resp => console.info('Loaded batch', step))
- batch.then(resp => state.dispatch('load_report_batch', step + 1))
}
}
})