Skip to content

Commit a87b588

Browse files
authored
feat: total in dashboard entries (#89)
1 parent 308215f commit a87b588

17 files changed

+129
-43
lines changed

dashboard/convert/entry.go

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func ToExternalEntry(entry model.DashboardEntry) (*gqlmodel.DashboardEntry, erro
4949
return &gqlmodel.DashboardEntry{
5050
ID: entry.ID,
5151
Title: entry.Title,
52+
Total: entry.Total,
5253
Pos: &pos,
5354
StatsSelection: stats,
5455
EntryType: ExternalEntryType(entry.Type),

dashboard/dbrange/ranges_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ func TestRanges(t *testing.T) {
150150
})
151151
require.EqualError(t, err, "dashboard range does not exist")
152152

153-
entry, err := resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "other", gqlmodel.InputStatsSelection{
153+
entry, err := resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "other", true, gqlmodel.InputStatsSelection{
154154
Interval: gqlmodel.StatsIntervalDaily,
155155
Tags: []string{"abc"},
156156
RangeID: &xrange.ID,

dashboard/entry/add.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
)
1818

1919
// AddDashboardEntry adds a dashboard entry.
20-
func (r *ResolverForEntry) AddDashboardEntry(ctx context.Context, dashboardID int, entryType gqlmodel.EntryType, title string, stats gqlmodel.InputStatsSelection, pos *gqlmodel.InputResponsiveDashboardEntryPos) (*gqlmodel.DashboardEntry, error) {
20+
func (r *ResolverForEntry) AddDashboardEntry(ctx context.Context, dashboardID int, entryType gqlmodel.EntryType, title string, total bool, stats gqlmodel.InputStatsSelection, pos *gqlmodel.InputResponsiveDashboardEntryPos) (*gqlmodel.DashboardEntry, error) {
2121
userID := auth.GetUser(ctx).ID
2222

2323
if _, err := util.FindDashboard(r.DB, userID, dashboardID); err != nil {
@@ -28,6 +28,7 @@ func (r *ResolverForEntry) AddDashboardEntry(ctx context.Context, dashboardID in
2828
Keys: strings.Join(stats.Tags, ","),
2929
Type: convert.InternalEntryType(entryType),
3030
Title: title,
31+
Total: total,
3132
DashboardID: dashboardID,
3233
Interval: convert.InternalInterval(stats.Interval),
3334
MobilePosition: convert.EmptyPos(),

dashboard/entry/entries_test.go

+24-15
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
func TestEntries(t *testing.T) {
1414
db := test.InMemoryDB(t)
1515
defer db.Close()
16+
var bVal bool
1617

1718
resolver := dashboard.NewResolverForDashboard(db.DB)
1819

@@ -35,7 +36,7 @@ func TestEntries(t *testing.T) {
3536
}
3637
require.Equal(t, expectAdded, dashboard)
3738

38-
_, err = resolver.AddDashboardEntry(user1, 5, gqlmodel.EntryTypeBarChart, "test", gqlmodel.InputStatsSelection{
39+
_, err = resolver.AddDashboardEntry(user1, 5, gqlmodel.EntryTypeBarChart, "test", false, gqlmodel.InputStatsSelection{
3940
Interval: "",
4041
Tags: []string{"hhol"},
4142
ExcludeTags: nil,
@@ -47,7 +48,7 @@ func TestEntries(t *testing.T) {
4748
},
4849
}, nil)
4950
require.EqualError(t, err, "dashboard does not exist")
50-
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", gqlmodel.InputStatsSelection{
51+
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", false, gqlmodel.InputStatsSelection{
5152
Interval: gqlmodel.StatsIntervalHourly,
5253
Tags: []string{"hhol"},
5354
ExcludeTags: nil,
@@ -59,7 +60,7 @@ func TestEntries(t *testing.T) {
5960
},
6061
}, nil)
6162
require.EqualError(t, err, "dashboard range does not exist")
62-
_, err = resolver.AddDashboardEntry(user2, 1, gqlmodel.EntryTypeBarChart, "test", gqlmodel.InputStatsSelection{
63+
_, err = resolver.AddDashboardEntry(user2, 1, gqlmodel.EntryTypeBarChart, "test", false, gqlmodel.InputStatsSelection{
6364
Interval: "doubly",
6465
Tags: []string{"hhol"},
6566
ExcludeTags: nil,
@@ -71,7 +72,7 @@ func TestEntries(t *testing.T) {
7172
},
7273
}, nil)
7374
require.EqualError(t, err, "dashboard does not exist")
74-
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", gqlmodel.InputStatsSelection{
75+
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", false, gqlmodel.InputStatsSelection{
7576
Interval: gqlmodel.StatsIntervalDaily,
7677
Tags: []string{"hhol"},
7778
ExcludeTags: nil,
@@ -83,7 +84,7 @@ func TestEntries(t *testing.T) {
8384
},
8485
}, nil)
8586
require.EqualError(t, err, "range to (now-2) invalid: expected unit at the end but got nothing")
86-
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", gqlmodel.InputStatsSelection{
87+
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", false, gqlmodel.InputStatsSelection{
8788
Interval: gqlmodel.StatsIntervalDaily,
8889
Tags: []string{"hhol"},
8990
ExcludeTags: nil,
@@ -95,7 +96,7 @@ func TestEntries(t *testing.T) {
9596
},
9697
}, nil)
9798
require.EqualError(t, err, "range from (now-2) invalid: expected unit at the end but got nothing")
98-
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", gqlmodel.InputStatsSelection{
99+
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", false, gqlmodel.InputStatsSelection{
99100
Interval: gqlmodel.StatsIntervalDaily,
100101
Tags: []string{},
101102
ExcludeTags: nil,
@@ -108,7 +109,7 @@ func TestEntries(t *testing.T) {
108109
}, nil)
109110
require.EqualError(t, err, "at least one tag is required")
110111

111-
entry, err := resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", gqlmodel.InputStatsSelection{
112+
entry, err := resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", false, gqlmodel.InputStatsSelection{
112113
Interval: gqlmodel.StatsIntervalDaily,
113114
Tags: []string{"abc"},
114115
ExcludeTags: nil,
@@ -128,6 +129,7 @@ func TestEntries(t *testing.T) {
128129
expectedEntry := &gqlmodel.DashboardEntry{
129130
ID: 1,
130131
Title: "test",
132+
Total: false,
131133
StatsSelection: &gqlmodel.StatsSelection{
132134
Interval: gqlmodel.StatsIntervalDaily,
133135
Tags: []string{"abc"},
@@ -173,7 +175,7 @@ func TestEntries(t *testing.T) {
173175
},
174176
})
175177
require.NoError(t, err)
176-
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "other", gqlmodel.InputStatsSelection{
178+
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "other", false, gqlmodel.InputStatsSelection{
177179
Interval: gqlmodel.StatsIntervalDaily,
178180
Tags: []string{"abc"},
179181
RangeID: p(xrange.ID),
@@ -188,11 +190,11 @@ func TestEntries(t *testing.T) {
188190
require.EqualError(t, err, "range is used in entries: other")
189191

190192
chart := gqlmodel.EntryTypePieChart
191-
_, err = resolver.UpdateDashboardEntry(user2, 1, &chart, nil, nil, nil)
193+
_, err = resolver.UpdateDashboardEntry(user2, 1, &chart, nil, nil, nil, nil)
192194
require.EqualError(t, err, "dashboard does not exist")
193-
_, err = resolver.UpdateDashboardEntry(user1, 3, &chart, nil, nil, nil)
195+
_, err = resolver.UpdateDashboardEntry(user1, 3, &chart, nil, nil, nil, nil)
194196
require.EqualError(t, err, "entry does not exist")
195-
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &gqlmodel.InputStatsSelection{
197+
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &bVal, &gqlmodel.InputStatsSelection{
196198
Interval: gqlmodel.StatsIntervalDaily,
197199
Tags: []string{"kek"},
198200
ExcludeTags: nil,
@@ -204,7 +206,7 @@ func TestEntries(t *testing.T) {
204206
},
205207
}, nil)
206208
require.EqualError(t, err, "range from (now-2) invalid: expected unit at the end but got nothing")
207-
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &gqlmodel.InputStatsSelection{
209+
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &bVal, &gqlmodel.InputStatsSelection{
208210
Interval: gqlmodel.StatsIntervalDaily,
209211
Tags: []string{"kek"},
210212
ExcludeTags: nil,
@@ -222,6 +224,7 @@ func TestEntries(t *testing.T) {
222224
{
223225
ID: 1,
224226
Title: "test",
227+
Total: false,
225228
StatsSelection: &gqlmodel.StatsSelection{
226229
Interval: gqlmodel.StatsIntervalDaily,
227230
Tags: []string{"abc"},
@@ -256,6 +259,7 @@ func TestEntries(t *testing.T) {
256259
{
257260
ID: 2,
258261
Title: "other",
262+
Total: false,
259263
StatsSelection: &gqlmodel.StatsSelection{
260264
Interval: gqlmodel.StatsIntervalDaily,
261265
Tags: []string{"abc"},
@@ -284,7 +288,7 @@ func TestEntries(t *testing.T) {
284288
EntryType: gqlmodel.EntryTypeBarChart,
285289
},
286290
}, dashboards[0].Items)
287-
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &gqlmodel.InputStatsSelection{
291+
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &bVal, &gqlmodel.InputStatsSelection{
288292
Interval: gqlmodel.StatsIntervalDaily,
289293
Tags: []string{"kek"},
290294
ExcludeTags: nil,
@@ -308,6 +312,7 @@ func TestEntries(t *testing.T) {
308312
{
309313
ID: 1,
310314
Title: "cool title",
315+
Total: false,
311316
StatsSelection: &gqlmodel.StatsSelection{
312317
Interval: gqlmodel.StatsIntervalDaily,
313318
Tags: []string{"kek"},
@@ -342,6 +347,7 @@ func TestEntries(t *testing.T) {
342347
{
343348
ID: 2,
344349
Title: "other",
350+
Total: false,
345351
StatsSelection: &gqlmodel.StatsSelection{
346352
Interval: gqlmodel.StatsIntervalDaily,
347353
Tags: []string{"abc"},
@@ -371,7 +377,7 @@ func TestEntries(t *testing.T) {
371377
},
372378
}, dashboards[0].Items)
373379

374-
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &gqlmodel.InputStatsSelection{
380+
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &bVal, &gqlmodel.InputStatsSelection{
375381
Interval: gqlmodel.StatsIntervalDaily,
376382
Tags: []string{"kek"},
377383
ExcludeTags: nil,
@@ -385,7 +391,7 @@ func TestEntries(t *testing.T) {
385391
}})
386392
require.EqualError(t, err, "dashboard range does not exist")
387393

388-
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &gqlmodel.InputStatsSelection{
394+
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &bVal, &gqlmodel.InputStatsSelection{
389395
Interval: gqlmodel.StatsIntervalDaily,
390396
Tags: []string{"kek"},
391397
ExcludeTags: nil,
@@ -405,6 +411,7 @@ func TestEntries(t *testing.T) {
405411
{
406412
ID: 1,
407413
Title: "cool title",
414+
Total: false,
408415
StatsSelection: &gqlmodel.StatsSelection{
409416
Interval: gqlmodel.StatsIntervalDaily,
410417
Tags: []string{"kek"},
@@ -435,6 +442,7 @@ func TestEntries(t *testing.T) {
435442
{
436443
ID: 2,
437444
Title: "other",
445+
Total: false,
438446
StatsSelection: &gqlmodel.StatsSelection{
439447
Interval: gqlmodel.StatsIntervalDaily,
440448
Tags: []string{"abc"},
@@ -479,6 +487,7 @@ func TestEntries(t *testing.T) {
479487
{
480488
ID: 2,
481489
Title: "other",
490+
Total: false,
482491
StatsSelection: &gqlmodel.StatsSelection{
483492
Interval: gqlmodel.StatsIntervalDaily,
484493
Tags: []string{"abc"},

dashboard/entry/update.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
)
1717

1818
// UpdateDashboardEntry updates a dashboard entry.
19-
func (r *ResolverForEntry) UpdateDashboardEntry(ctx context.Context, id int, entryType *gqlmodel.EntryType, title *string, stats *gqlmodel.InputStatsSelection, pos *gqlmodel.InputResponsiveDashboardEntryPos) (*gqlmodel.DashboardEntry, error) {
19+
func (r *ResolverForEntry) UpdateDashboardEntry(ctx context.Context, id int, entryType *gqlmodel.EntryType, title *string, total *bool, stats *gqlmodel.InputStatsSelection, pos *gqlmodel.InputResponsiveDashboardEntryPos) (*gqlmodel.DashboardEntry, error) {
2020
userID := auth.GetUser(ctx).ID
2121

2222
entry, err := util.FindDashboardEntry(r.DB, id)
@@ -31,6 +31,11 @@ func (r *ResolverForEntry) UpdateDashboardEntry(ctx context.Context, id int, ent
3131
if title != nil {
3232
entry.Title = *title
3333
}
34+
35+
if total != nil {
36+
entry.Total = *total
37+
}
38+
3439
if stats != nil {
3540
if stats.RangeID != nil {
3641
if _, err := util.FindDashboardRange(r.DB, *stats.RangeID); err != nil {

model/dashboard.go

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type DashboardEntry struct {
2929
ID int `gorm:"primary_key;unique_index;AUTO_INCREMENT"`
3030
DashboardID int `gorm:"type:int REFERENCES dashboards(id) ON DELETE CASCADE"`
3131
Title string
32+
Total bool `gorm:"default:false"`
3233
Type DashboardType
3334
Keys string
3435
Interval Interval

schema.graphql

+3-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ type RootMutation {
4040
updateDashboardRange(rangeId: Int!, range: InputNamedDateRange!): NamedDateRange
4141
removeDashboardRange(rangeId: Int!): NamedDateRange
4242

43-
addDashboardEntry(dashboardId: Int!, entryType: EntryType!, title: String!, stats: InputStatsSelection!, pos: InputResponsiveDashboardEntryPos): DashboardEntry @hasRole(role: USER)
44-
updateDashboardEntry(entryId: Int!, entryType: EntryType, title: String, stats: InputStatsSelection, pos: InputResponsiveDashboardEntryPos): DashboardEntry @hasRole(role: USER)
43+
addDashboardEntry(dashboardId: Int!, entryType: EntryType!, title: String!, total: Boolean!, stats: InputStatsSelection!, pos: InputResponsiveDashboardEntryPos): DashboardEntry @hasRole(role: USER)
44+
updateDashboardEntry(entryId: Int!, entryType: EntryType, title: String, total: Boolean, stats: InputStatsSelection, pos: InputResponsiveDashboardEntryPos): DashboardEntry @hasRole(role: USER)
4545
removeDashboardEntry(id: Int!): DashboardEntry! @hasRole(role: USER)
4646

4747
setUserSettings(settings: InputUserSettings!): UserSettings! @hasRole(role: USER)
@@ -251,6 +251,7 @@ input InputRelativeOrStaticRange {
251251
type DashboardEntry {
252252
id: Int!
253253
title: String!
254+
total: Boolean!
254255
statsSelection: StatsSelection!
255256
pos: ResponsiveDashboardEntryPos!
256257
entryType: EntryType!

ui/src/dashboard/DashboardPage.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ const newEntry = (): Dashboards_dashboards_items => {
7474
__typename: 'DashboardEntryPos',
7575
},
7676
},
77+
total: false,
7778
};
7879
};
7980

ui/src/dashboard/Entry/AddPopup.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export const AddPopup: React.FC<EditPopupProps> = ({
7878
dashboardId,
7979
entryType: entry.entryType,
8080
title: entry.title,
81+
total: entry.total,
8182
stats: {
8283
tags: entry.statsSelection.tags,
8384
interval: entry.statsSelection.interval,

ui/src/dashboard/Entry/DashboardBarChart.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface DashboardPieChartProps {
1212
entries: Stats_stats[];
1313
interval: StatsInterval;
1414
type: 'stacked' | 'normal';
15+
total: boolean;
1516
}
1617

1718
interface Indexed {
@@ -20,7 +21,7 @@ interface Indexed {
2021
data: Record<string, number>;
2122
}
2223

23-
export const DashboardBarChart: React.FC<DashboardPieChartProps> = ({entries, interval, type}) => {
24+
export const DashboardBarChart: React.FC<DashboardPieChartProps> = ({entries, interval, type, total}) => {
2425
const indexedEntries: Indexed[] = entries
2526
.map((entry) => {
2627
return {
@@ -46,7 +47,7 @@ export const DashboardBarChart: React.FC<DashboardPieChartProps> = ({entries, in
4647
<BarChart data={indexedEntries}>
4748
<CartesianGrid strokeDasharray="3 3" />
4849
<YAxis type="number" unit={unit.short} />
49-
<Tooltip content={<TagTooltip dateFormat={dateFormat} />} />
50+
<Tooltip content={<TagTooltip dateFormat={dateFormat} total={total} />} />
5051
<Legend />
5152
<XAxis dataKey={(entry) => dateFormat(moment(entry.start))} interval={'preserveStartEnd'} />
5253

ui/src/dashboard/Entry/DashboardEntry.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ const SpecificDashboardEntry: React.FC<{entry: Dashboards_dashboards_items; rang
8888
</Center>
8989
);
9090
}
91-
return <DashboardBarChart entries={entries} interval={interval} type="normal" />;
91+
return <DashboardBarChart entries={entries} interval={interval} type="normal" total={entry.total} />;
9292
case EntryType.StackedBarChart:
9393
if (entries.length === 0) {
9494
return (
@@ -97,7 +97,7 @@ const SpecificDashboardEntry: React.FC<{entry: Dashboards_dashboards_items; rang
9797
</Center>
9898
);
9999
}
100-
return <DashboardBarChart entries={entries} interval={interval} type="stacked" />;
100+
return <DashboardBarChart entries={entries} interval={interval} type="stacked" total={entry.total} />;
101101
case EntryType.LineChart:
102102
if (entries.length === 0) {
103103
return (
@@ -106,7 +106,7 @@ const SpecificDashboardEntry: React.FC<{entry: Dashboards_dashboards_items; rang
106106
</Center>
107107
);
108108
}
109-
return <DashboardLineChart entries={entries} interval={interval} />;
109+
return <DashboardLineChart entries={entries} interval={interval} total={entry.total} />;
110110
case EntryType.VerticalTable:
111111
if (entries.length === 0) {
112112
return (
@@ -115,7 +115,7 @@ const SpecificDashboardEntry: React.FC<{entry: Dashboards_dashboards_items; rang
115115
</Center>
116116
);
117117
}
118-
return <DashboardTable mode="vertical" entries={entries} interval={interval} />;
118+
return <DashboardTable mode="vertical" entries={entries} interval={interval} total={entry.total} />;
119119
case EntryType.HorizontalTable:
120120
if (entries.length === 0) {
121121
return (
@@ -124,7 +124,7 @@ const SpecificDashboardEntry: React.FC<{entry: Dashboards_dashboards_items; rang
124124
</Center>
125125
);
126126
}
127-
return <DashboardTable mode="horizontal" entries={entries} interval={interval} />;
127+
return <DashboardTable mode="horizontal" entries={entries} interval={interval} total={entry.total} />;
128128
default:
129129
return expectNever(entry.entryType);
130130
}

0 commit comments

Comments
 (0)