mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
feat: introduce machine summaries (resolve #48)
This commit is contained in:
parent
2eccb7a468
commit
12cc4cd9cf
@ -80,6 +80,7 @@ INSERT INTO aliases (`type`, `user_id`, `key`, `value`) VALUES (0, 'your_usernam
|
|||||||
* Language ~ type **1**
|
* Language ~ type **1**
|
||||||
* Editor ~ type **2**
|
* Editor ~ type **2**
|
||||||
* OS ~ type **3**
|
* OS ~ type **3**
|
||||||
|
* Machine ~ type **4**
|
||||||
|
|
||||||
**NOTE:** In order for the aliases to take effect for non-live statistics, you would either have to wait 24 hours for the cache to be invalidated or restart Wakapi.
|
**NOTE:** In order for the aliases to take effect for non-live statistics, you would either have to wait 24 hours for the cache to be invalidated or restart Wakapi.
|
||||||
|
|
||||||
|
@ -5,11 +5,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NSummaryTypes uint8 = 4
|
NSummaryTypes uint8 = 99
|
||||||
SummaryProject uint8 = 0
|
SummaryProject uint8 = 0
|
||||||
SummaryLanguage uint8 = 1
|
SummaryLanguage uint8 = 1
|
||||||
SummaryEditor uint8 = 2
|
SummaryEditor uint8 = 2
|
||||||
SummaryOS uint8 = 3
|
SummaryOS uint8 = 3
|
||||||
|
SummaryMachine uint8 = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
type Summary struct {
|
type Summary struct {
|
||||||
@ -21,6 +22,7 @@ type Summary struct {
|
|||||||
Languages []*SummaryItem `json:"languages"`
|
Languages []*SummaryItem `json:"languages"`
|
||||||
Editors []*SummaryItem `json:"editors"`
|
Editors []*SummaryItem `json:"editors"`
|
||||||
OperatingSystems []*SummaryItem `json:"operating_systems"`
|
OperatingSystems []*SummaryItem `json:"operating_systems"`
|
||||||
|
Machines []*SummaryItem `json:"machines"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SummaryItem struct {
|
type SummaryItem struct {
|
||||||
|
@ -65,12 +65,13 @@ func (srv *SummaryService) Construct(from, to time.Time, user *models.User, reco
|
|||||||
heartbeats = append(heartbeats, hb...)
|
heartbeats = append(heartbeats, hb...)
|
||||||
}
|
}
|
||||||
|
|
||||||
types := []uint8{models.SummaryProject, models.SummaryLanguage, models.SummaryEditor, models.SummaryOS}
|
types := []uint8{models.SummaryProject, models.SummaryLanguage, models.SummaryEditor, models.SummaryOS, models.SummaryMachine}
|
||||||
|
|
||||||
var projectItems []*models.SummaryItem
|
var projectItems []*models.SummaryItem
|
||||||
var languageItems []*models.SummaryItem
|
var languageItems []*models.SummaryItem
|
||||||
var editorItems []*models.SummaryItem
|
var editorItems []*models.SummaryItem
|
||||||
var osItems []*models.SummaryItem
|
var osItems []*models.SummaryItem
|
||||||
|
var machineItems []*models.SummaryItem
|
||||||
|
|
||||||
if err := srv.AliasService.LoadUserAliases(user.ID); err != nil {
|
if err := srv.AliasService.LoadUserAliases(user.ID); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -92,6 +93,8 @@ func (srv *SummaryService) Construct(from, to time.Time, user *models.User, reco
|
|||||||
editorItems = item.Items
|
editorItems = item.Items
|
||||||
case models.SummaryOS:
|
case models.SummaryOS:
|
||||||
osItems = item.Items
|
osItems = item.Items
|
||||||
|
case models.SummaryMachine:
|
||||||
|
machineItems = item.Items
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(c)
|
close(c)
|
||||||
@ -119,6 +122,7 @@ func (srv *SummaryService) Construct(from, to time.Time, user *models.User, reco
|
|||||||
Languages: languageItems,
|
Languages: languageItems,
|
||||||
Editors: editorItems,
|
Editors: editorItems,
|
||||||
OperatingSystems: osItems,
|
OperatingSystems: osItems,
|
||||||
|
Machines: machineItems,
|
||||||
}
|
}
|
||||||
|
|
||||||
allSummaries := []*models.Summary{aggregatedSummary}
|
allSummaries := []*models.Summary{aggregatedSummary}
|
||||||
@ -154,6 +158,7 @@ func (srv *SummaryService) GetByUserWithin(user *models.User, from, to time.Time
|
|||||||
Preload("Languages", "type = ?", models.SummaryLanguage).
|
Preload("Languages", "type = ?", models.SummaryLanguage).
|
||||||
Preload("Editors", "type = ?", models.SummaryEditor).
|
Preload("Editors", "type = ?", models.SummaryEditor).
|
||||||
Preload("OperatingSystems", "type = ?", models.SummaryOS).
|
Preload("OperatingSystems", "type = ?", models.SummaryOS).
|
||||||
|
Preload("Machines", "type = ?", models.SummaryMachine).
|
||||||
Find(&summaries).Error; err != nil {
|
Find(&summaries).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -187,6 +192,8 @@ func (srv *SummaryService) aggregateBy(heartbeats []*models.Heartbeat, summaryTy
|
|||||||
key = h.Language
|
key = h.Language
|
||||||
case models.SummaryOS:
|
case models.SummaryOS:
|
||||||
key = h.OperatingSystem
|
key = h.OperatingSystem
|
||||||
|
case models.SummaryMachine:
|
||||||
|
key = h.Machine
|
||||||
}
|
}
|
||||||
|
|
||||||
if key == "" {
|
if key == "" {
|
||||||
@ -276,6 +283,7 @@ func mergeSummaries(summaries []*models.Summary) (*models.Summary, error) {
|
|||||||
Languages: make([]*models.SummaryItem, 0),
|
Languages: make([]*models.SummaryItem, 0),
|
||||||
Editors: make([]*models.SummaryItem, 0),
|
Editors: make([]*models.SummaryItem, 0),
|
||||||
OperatingSystems: make([]*models.SummaryItem, 0),
|
OperatingSystems: make([]*models.SummaryItem, 0),
|
||||||
|
Machines: make([]*models.SummaryItem, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range summaries {
|
for _, s := range summaries {
|
||||||
@ -295,6 +303,7 @@ func mergeSummaries(summaries []*models.Summary) (*models.Summary, error) {
|
|||||||
finalSummary.Languages = mergeSummaryItems(finalSummary.Languages, s.Languages)
|
finalSummary.Languages = mergeSummaryItems(finalSummary.Languages, s.Languages)
|
||||||
finalSummary.Editors = mergeSummaryItems(finalSummary.Editors, s.Editors)
|
finalSummary.Editors = mergeSummaryItems(finalSummary.Editors, s.Editors)
|
||||||
finalSummary.OperatingSystems = mergeSummaryItems(finalSummary.OperatingSystems, s.OperatingSystems)
|
finalSummary.OperatingSystems = mergeSummaryItems(finalSummary.OperatingSystems, s.OperatingSystems)
|
||||||
|
finalSummary.Machines = mergeSummaryItems(finalSummary.Machines, s.Machines)
|
||||||
}
|
}
|
||||||
|
|
||||||
finalSummary.FromTime = minTime
|
finalSummary.FromTime = minTime
|
||||||
|
@ -5,6 +5,7 @@ const projectsCanvas = document.getElementById('chart-projects')
|
|||||||
const osCanvas = document.getElementById('chart-os')
|
const osCanvas = document.getElementById('chart-os')
|
||||||
const editorsCanvas = document.getElementById('chart-editor')
|
const editorsCanvas = document.getElementById('chart-editor')
|
||||||
const languagesCanvas = document.getElementById('chart-language')
|
const languagesCanvas = document.getElementById('chart-language')
|
||||||
|
const machinesCanvas = document.getElementById('chart-machine')
|
||||||
|
|
||||||
let charts = []
|
let charts = []
|
||||||
let resizeCount = 0
|
let resizeCount = 0
|
||||||
@ -135,10 +136,31 @@ function draw() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let machineChart = new Chart(machinesCanvas.getContext('2d'), {
|
||||||
|
type: 'pie',
|
||||||
|
data: {
|
||||||
|
datasets: [{
|
||||||
|
data: wakapiData.machines
|
||||||
|
.slice(0, Math.min(SHOW_TOP_N, wakapiData.machines.length))
|
||||||
|
.map(p => parseInt(p.total)),
|
||||||
|
backgroundColor: wakapiData.machines.map(p => getRandomColor(p.key))
|
||||||
|
}],
|
||||||
|
labels: wakapiData.machines
|
||||||
|
.slice(0, Math.min(SHOW_TOP_N, wakapiData.machines.length))
|
||||||
|
.map(p => p.key)
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
title: Object.assign(titleOptions, {text: `Machines (top ${SHOW_TOP_N})`}),
|
||||||
|
tooltips: getTooltipOptions('machines', 'pie'),
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
onResize: onChartResize
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
getTotal(wakapiData.operatingSystems)
|
getTotal(wakapiData.operatingSystems)
|
||||||
document.getElementById('grid-container').style.visibility = 'visible'
|
document.getElementById('grid-container').style.visibility = 'visible'
|
||||||
|
|
||||||
charts = [projectChart, osChart, editorChart, languageChart]
|
charts = [projectChart, osChart, editorChart, languageChart, machineChart]
|
||||||
|
|
||||||
charts.forEach(c => c.options.onResize(c.chart))
|
charts.forEach(c => c.options.onResize(c.chart))
|
||||||
equalizeHeights()
|
equalizeHeights()
|
||||||
|
@ -1 +1 @@
|
|||||||
1.7.6
|
1.8.0
|
@ -2,11 +2,13 @@
|
|||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
const languageColors = {{ .LanguageColors | json }}
|
||||||
|
|
||||||
let wakapiData = {}
|
let wakapiData = {}
|
||||||
let languageColors = {{ .LanguageColors | json }}
|
wakapiData.projects = {{ .Projects | json }}
|
||||||
wakapiData.projects = {{ .Projects | json }}
|
wakapiData.operatingSystems = {{ .OperatingSystems | json }}
|
||||||
wakapiData.operatingSystems = {{ .OperatingSystems | json }}
|
wakapiData.editors = {{ .Editors | json }}
|
||||||
wakapiData.editors = {{ .Editors | json }}
|
wakapiData.languages = {{ .Languages | json }}
|
||||||
wakapiData.languages = {{ .Languages | json }}
|
wakapiData.machines = {{ .Machines | json }}
|
||||||
</script>
|
</script>
|
||||||
<script src="assets/app.js"></script>
|
<script src="assets/app.js"></script>
|
@ -78,6 +78,11 @@
|
|||||||
<canvas id="chart-editor"></canvas>
|
<canvas id="chart-editor"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="w-full lg:w-1/2 p-1">
|
||||||
|
<div class="p-4 bg-white rounded shadow m-2" id="machine-container" style="height: 300px">
|
||||||
|
<canvas id="chart-machine"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user