Skip to content

Commit

Permalink
feat: total in dashboard entries (#89)
Browse files Browse the repository at this point in the history
  • Loading branch information
hulmgulm authored Nov 3, 2024
1 parent 308215f commit a87b588
Show file tree
Hide file tree
Showing 17 changed files with 129 additions and 43 deletions.
1 change: 1 addition & 0 deletions dashboard/convert/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func ToExternalEntry(entry model.DashboardEntry) (*gqlmodel.DashboardEntry, erro
return &gqlmodel.DashboardEntry{
ID: entry.ID,
Title: entry.Title,
Total: entry.Total,
Pos: &pos,
StatsSelection: stats,
EntryType: ExternalEntryType(entry.Type),
Expand Down
2 changes: 1 addition & 1 deletion dashboard/dbrange/ranges_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func TestRanges(t *testing.T) {
})
require.EqualError(t, err, "dashboard range does not exist")

entry, err := resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "other", gqlmodel.InputStatsSelection{
entry, err := resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "other", true, gqlmodel.InputStatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"abc"},
RangeID: &xrange.ID,
Expand Down
3 changes: 2 additions & 1 deletion dashboard/entry/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
)

// AddDashboardEntry adds a dashboard entry.
func (r *ResolverForEntry) AddDashboardEntry(ctx context.Context, dashboardID int, entryType gqlmodel.EntryType, title string, stats gqlmodel.InputStatsSelection, pos *gqlmodel.InputResponsiveDashboardEntryPos) (*gqlmodel.DashboardEntry, error) {
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) {
userID := auth.GetUser(ctx).ID

if _, err := util.FindDashboard(r.DB, userID, dashboardID); err != nil {
Expand All @@ -28,6 +28,7 @@ func (r *ResolverForEntry) AddDashboardEntry(ctx context.Context, dashboardID in
Keys: strings.Join(stats.Tags, ","),
Type: convert.InternalEntryType(entryType),
Title: title,
Total: total,
DashboardID: dashboardID,
Interval: convert.InternalInterval(stats.Interval),
MobilePosition: convert.EmptyPos(),
Expand Down
39 changes: 24 additions & 15 deletions dashboard/entry/entries_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
func TestEntries(t *testing.T) {
db := test.InMemoryDB(t)
defer db.Close()
var bVal bool

resolver := dashboard.NewResolverForDashboard(db.DB)

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

_, err = resolver.AddDashboardEntry(user1, 5, gqlmodel.EntryTypeBarChart, "test", gqlmodel.InputStatsSelection{
_, err = resolver.AddDashboardEntry(user1, 5, gqlmodel.EntryTypeBarChart, "test", false, gqlmodel.InputStatsSelection{
Interval: "",
Tags: []string{"hhol"},
ExcludeTags: nil,
Expand All @@ -47,7 +48,7 @@ func TestEntries(t *testing.T) {
},
}, nil)
require.EqualError(t, err, "dashboard does not exist")
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", gqlmodel.InputStatsSelection{
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", false, gqlmodel.InputStatsSelection{
Interval: gqlmodel.StatsIntervalHourly,
Tags: []string{"hhol"},
ExcludeTags: nil,
Expand All @@ -59,7 +60,7 @@ func TestEntries(t *testing.T) {
},
}, nil)
require.EqualError(t, err, "dashboard range does not exist")
_, err = resolver.AddDashboardEntry(user2, 1, gqlmodel.EntryTypeBarChart, "test", gqlmodel.InputStatsSelection{
_, err = resolver.AddDashboardEntry(user2, 1, gqlmodel.EntryTypeBarChart, "test", false, gqlmodel.InputStatsSelection{
Interval: "doubly",
Tags: []string{"hhol"},
ExcludeTags: nil,
Expand All @@ -71,7 +72,7 @@ func TestEntries(t *testing.T) {
},
}, nil)
require.EqualError(t, err, "dashboard does not exist")
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", gqlmodel.InputStatsSelection{
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", false, gqlmodel.InputStatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"hhol"},
ExcludeTags: nil,
Expand All @@ -83,7 +84,7 @@ func TestEntries(t *testing.T) {
},
}, nil)
require.EqualError(t, err, "range to (now-2) invalid: expected unit at the end but got nothing")
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", gqlmodel.InputStatsSelection{
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", false, gqlmodel.InputStatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"hhol"},
ExcludeTags: nil,
Expand All @@ -95,7 +96,7 @@ func TestEntries(t *testing.T) {
},
}, nil)
require.EqualError(t, err, "range from (now-2) invalid: expected unit at the end but got nothing")
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", gqlmodel.InputStatsSelection{
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", false, gqlmodel.InputStatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{},
ExcludeTags: nil,
Expand All @@ -108,7 +109,7 @@ func TestEntries(t *testing.T) {
}, nil)
require.EqualError(t, err, "at least one tag is required")

entry, err := resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", gqlmodel.InputStatsSelection{
entry, err := resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "test", false, gqlmodel.InputStatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"abc"},
ExcludeTags: nil,
Expand All @@ -128,6 +129,7 @@ func TestEntries(t *testing.T) {
expectedEntry := &gqlmodel.DashboardEntry{
ID: 1,
Title: "test",
Total: false,
StatsSelection: &gqlmodel.StatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"abc"},
Expand Down Expand Up @@ -173,7 +175,7 @@ func TestEntries(t *testing.T) {
},
})
require.NoError(t, err)
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "other", gqlmodel.InputStatsSelection{
_, err = resolver.AddDashboardEntry(user1, 1, gqlmodel.EntryTypeBarChart, "other", false, gqlmodel.InputStatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"abc"},
RangeID: p(xrange.ID),
Expand All @@ -188,11 +190,11 @@ func TestEntries(t *testing.T) {
require.EqualError(t, err, "range is used in entries: other")

chart := gqlmodel.EntryTypePieChart
_, err = resolver.UpdateDashboardEntry(user2, 1, &chart, nil, nil, nil)
_, err = resolver.UpdateDashboardEntry(user2, 1, &chart, nil, nil, nil, nil)
require.EqualError(t, err, "dashboard does not exist")
_, err = resolver.UpdateDashboardEntry(user1, 3, &chart, nil, nil, nil)
_, err = resolver.UpdateDashboardEntry(user1, 3, &chart, nil, nil, nil, nil)
require.EqualError(t, err, "entry does not exist")
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &gqlmodel.InputStatsSelection{
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &bVal, &gqlmodel.InputStatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"kek"},
ExcludeTags: nil,
Expand All @@ -204,7 +206,7 @@ func TestEntries(t *testing.T) {
},
}, nil)
require.EqualError(t, err, "range from (now-2) invalid: expected unit at the end but got nothing")
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &gqlmodel.InputStatsSelection{
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &bVal, &gqlmodel.InputStatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"kek"},
ExcludeTags: nil,
Expand All @@ -222,6 +224,7 @@ func TestEntries(t *testing.T) {
{
ID: 1,
Title: "test",
Total: false,
StatsSelection: &gqlmodel.StatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"abc"},
Expand Down Expand Up @@ -256,6 +259,7 @@ func TestEntries(t *testing.T) {
{
ID: 2,
Title: "other",
Total: false,
StatsSelection: &gqlmodel.StatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"abc"},
Expand Down Expand Up @@ -284,7 +288,7 @@ func TestEntries(t *testing.T) {
EntryType: gqlmodel.EntryTypeBarChart,
},
}, dashboards[0].Items)
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &gqlmodel.InputStatsSelection{
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &bVal, &gqlmodel.InputStatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"kek"},
ExcludeTags: nil,
Expand All @@ -308,6 +312,7 @@ func TestEntries(t *testing.T) {
{
ID: 1,
Title: "cool title",
Total: false,
StatsSelection: &gqlmodel.StatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"kek"},
Expand Down Expand Up @@ -342,6 +347,7 @@ func TestEntries(t *testing.T) {
{
ID: 2,
Title: "other",
Total: false,
StatsSelection: &gqlmodel.StatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"abc"},
Expand Down Expand Up @@ -371,7 +377,7 @@ func TestEntries(t *testing.T) {
},
}, dashboards[0].Items)

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

_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &gqlmodel.InputStatsSelection{
_, err = resolver.UpdateDashboardEntry(user1, 1, &chart, s("cool title"), &bVal, &gqlmodel.InputStatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"kek"},
ExcludeTags: nil,
Expand All @@ -405,6 +411,7 @@ func TestEntries(t *testing.T) {
{
ID: 1,
Title: "cool title",
Total: false,
StatsSelection: &gqlmodel.StatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"kek"},
Expand Down Expand Up @@ -435,6 +442,7 @@ func TestEntries(t *testing.T) {
{
ID: 2,
Title: "other",
Total: false,
StatsSelection: &gqlmodel.StatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"abc"},
Expand Down Expand Up @@ -479,6 +487,7 @@ func TestEntries(t *testing.T) {
{
ID: 2,
Title: "other",
Total: false,
StatsSelection: &gqlmodel.StatsSelection{
Interval: gqlmodel.StatsIntervalDaily,
Tags: []string{"abc"},
Expand Down
7 changes: 6 additions & 1 deletion dashboard/entry/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
)

// UpdateDashboardEntry updates a dashboard entry.
func (r *ResolverForEntry) UpdateDashboardEntry(ctx context.Context, id int, entryType *gqlmodel.EntryType, title *string, stats *gqlmodel.InputStatsSelection, pos *gqlmodel.InputResponsiveDashboardEntryPos) (*gqlmodel.DashboardEntry, error) {
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) {
userID := auth.GetUser(ctx).ID

entry, err := util.FindDashboardEntry(r.DB, id)
Expand All @@ -31,6 +31,11 @@ func (r *ResolverForEntry) UpdateDashboardEntry(ctx context.Context, id int, ent
if title != nil {
entry.Title = *title
}

if total != nil {
entry.Total = *total
}

if stats != nil {
if stats.RangeID != nil {
if _, err := util.FindDashboardRange(r.DB, *stats.RangeID); err != nil {
Expand Down
1 change: 1 addition & 0 deletions model/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type DashboardEntry struct {
ID int `gorm:"primary_key;unique_index;AUTO_INCREMENT"`
DashboardID int `gorm:"type:int REFERENCES dashboards(id) ON DELETE CASCADE"`
Title string
Total bool `gorm:"default:false"`
Type DashboardType
Keys string
Interval Interval
Expand Down
5 changes: 3 additions & 2 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ type RootMutation {
updateDashboardRange(rangeId: Int!, range: InputNamedDateRange!): NamedDateRange
removeDashboardRange(rangeId: Int!): NamedDateRange

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

setUserSettings(settings: InputUserSettings!): UserSettings! @hasRole(role: USER)
Expand Down Expand Up @@ -251,6 +251,7 @@ input InputRelativeOrStaticRange {
type DashboardEntry {
id: Int!
title: String!
total: Boolean!
statsSelection: StatsSelection!
pos: ResponsiveDashboardEntryPos!
entryType: EntryType!
Expand Down
1 change: 1 addition & 0 deletions ui/src/dashboard/DashboardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ const newEntry = (): Dashboards_dashboards_items => {
__typename: 'DashboardEntryPos',
},
},
total: false,
};
};

Expand Down
1 change: 1 addition & 0 deletions ui/src/dashboard/Entry/AddPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export const AddPopup: React.FC<EditPopupProps> = ({
dashboardId,
entryType: entry.entryType,
title: entry.title,
total: entry.total,
stats: {
tags: entry.statsSelection.tags,
interval: entry.statsSelection.interval,
Expand Down
5 changes: 3 additions & 2 deletions ui/src/dashboard/Entry/DashboardBarChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface DashboardPieChartProps {
entries: Stats_stats[];
interval: StatsInterval;
type: 'stacked' | 'normal';
total: boolean;
}

interface Indexed {
Expand All @@ -20,7 +21,7 @@ interface Indexed {
data: Record<string, number>;
}

export const DashboardBarChart: React.FC<DashboardPieChartProps> = ({entries, interval, type}) => {
export const DashboardBarChart: React.FC<DashboardPieChartProps> = ({entries, interval, type, total}) => {
const indexedEntries: Indexed[] = entries
.map((entry) => {
return {
Expand All @@ -46,7 +47,7 @@ export const DashboardBarChart: React.FC<DashboardPieChartProps> = ({entries, in
<BarChart data={indexedEntries}>
<CartesianGrid strokeDasharray="3 3" />
<YAxis type="number" unit={unit.short} />
<Tooltip content={<TagTooltip dateFormat={dateFormat} />} />
<Tooltip content={<TagTooltip dateFormat={dateFormat} total={total} />} />
<Legend />
<XAxis dataKey={(entry) => dateFormat(moment(entry.start))} interval={'preserveStartEnd'} />

Expand Down
10 changes: 5 additions & 5 deletions ui/src/dashboard/Entry/DashboardEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ const SpecificDashboardEntry: React.FC<{entry: Dashboards_dashboards_items; rang
</Center>
);
}
return <DashboardBarChart entries={entries} interval={interval} type="normal" />;
return <DashboardBarChart entries={entries} interval={interval} type="normal" total={entry.total} />;
case EntryType.StackedBarChart:
if (entries.length === 0) {
return (
Expand All @@ -97,7 +97,7 @@ const SpecificDashboardEntry: React.FC<{entry: Dashboards_dashboards_items; rang
</Center>
);
}
return <DashboardBarChart entries={entries} interval={interval} type="stacked" />;
return <DashboardBarChart entries={entries} interval={interval} type="stacked" total={entry.total} />;
case EntryType.LineChart:
if (entries.length === 0) {
return (
Expand All @@ -106,7 +106,7 @@ const SpecificDashboardEntry: React.FC<{entry: Dashboards_dashboards_items; rang
</Center>
);
}
return <DashboardLineChart entries={entries} interval={interval} />;
return <DashboardLineChart entries={entries} interval={interval} total={entry.total} />;
case EntryType.VerticalTable:
if (entries.length === 0) {
return (
Expand All @@ -115,7 +115,7 @@ const SpecificDashboardEntry: React.FC<{entry: Dashboards_dashboards_items; rang
</Center>
);
}
return <DashboardTable mode="vertical" entries={entries} interval={interval} />;
return <DashboardTable mode="vertical" entries={entries} interval={interval} total={entry.total} />;
case EntryType.HorizontalTable:
if (entries.length === 0) {
return (
Expand All @@ -124,7 +124,7 @@ const SpecificDashboardEntry: React.FC<{entry: Dashboards_dashboards_items; rang
</Center>
);
}
return <DashboardTable mode="horizontal" entries={entries} interval={interval} />;
return <DashboardTable mode="horizontal" entries={entries} interval={interval} total={entry.total} />;
default:
return expectNever(entry.entryType);
}
Expand Down
Loading

0 comments on commit a87b588

Please sign in to comment.