diff --git a/backend/pkg/api/data_access/user.go b/backend/pkg/api/data_access/user.go index 598f83995..c7c22d9cf 100644 --- a/backend/pkg/api/data_access/user.go +++ b/backend/pkg/api/data_access/user.go @@ -287,7 +287,10 @@ func (d *DataAccessService) GetUserInfo(ctx context.Context, userId uint64) (*t. }{} err = d.userReader.GetContext(ctx, &result, `SELECT email, COALESCE(user_group, '') as user_group FROM users WHERE id = $1`, userId) if err != nil { - return nil, fmt.Errorf("error getting userEmail for user %v: %w", userId, err) + if errors.Is(err, sql.ErrNoRows) { + return nil, fmt.Errorf("%w: user not found", ErrNotFound) + } + return nil, err } userInfo.Email = result.Email userInfo.UserGroup = result.UserGroup @@ -764,7 +767,7 @@ func (d *DataAccessService) GetUserDashboards(ctx context.Context, userId uint64 err := wg.Wait() if err != nil { - return nil, fmt.Errorf("error retrieving user dashboards data: %v", err) + return nil, fmt.Errorf("error retrieving user dashboards data: %w", err) } // Fill the result diff --git a/backend/pkg/api/data_access/vdb_management.go b/backend/pkg/api/data_access/vdb_management.go index 9163a51ab..b523103c6 100644 --- a/backend/pkg/api/data_access/vdb_management.go +++ b/backend/pkg/api/data_access/vdb_management.go @@ -148,7 +148,7 @@ func (d *DataAccessService) GetValidatorDashboardInfo(ctx context.Context, dashb err := wg.Wait() if err != nil { - return nil, fmt.Errorf("error retrieving user dashboards data: %v", err) + return nil, fmt.Errorf("error retrieving user dashboards data: %w", err) } return result, nil @@ -329,7 +329,7 @@ func (d *DataAccessService) GetValidatorDashboardOverview(ctx context.Context, d validators, err := d.getDashboardValidators(ctx, dashboardId, nil) if err != nil { - return fmt.Errorf("error retrieving validators from dashboard id: %v", err) + return fmt.Errorf("error retrieving validators from dashboard id: %w", err) } if dashboardId.Validators != nil || dashboardId.AggregateGroups { @@ -475,7 +475,7 @@ func (d *DataAccessService) GetValidatorDashboardOverview(ctx context.Context, d query, args, err := ds.Prepared(true).ToSQL() if err != nil { - return fmt.Errorf("error preparing query: %v", err) + return fmt.Errorf("error preparing query: %w", err) } err = d.clickhouseReader.GetContext(ctx, &queryResult, query, args...) @@ -511,7 +511,7 @@ func (d *DataAccessService) GetValidatorDashboardOverview(ctx context.Context, d err = eg.Wait() if err != nil { - return nil, fmt.Errorf("error retrieving validator dashboard overview data: %v", err) + return nil, fmt.Errorf("error retrieving validator dashboard overview data: %w", err) } return &data, nil diff --git a/backend/pkg/api/handlers/common.go b/backend/pkg/api/handlers/common.go index 3a895c481..ca585724b 100644 --- a/backend/pkg/api/handlers/common.go +++ b/backend/pkg/api/handlers/common.go @@ -566,7 +566,7 @@ func checkSort[T enums.EnumFactory[T]](v *validationError, sortString string) *t return nil } if len(sortSplit) == 1 { - sortSplit = append(sortSplit, "") + sortSplit = append(sortSplit, ":asc") } sortCol := checkEnum[T](v, sortSplit[0], "sort") order := v.parseSortOrder(sortSplit[1]) diff --git a/backend/pkg/api/handlers/public.go b/backend/pkg/api/handlers/public.go index a06e798c3..95df23ea7 100644 --- a/backend/pkg/api/handlers/public.go +++ b/backend/pkg/api/handlers/public.go @@ -135,7 +135,7 @@ func (h *HandlerService) PublicPutAccountDashboardTransactionsSettings(w http.Re // // @Description Create a new validator dashboard. **Note**: New dashboards will automatically have a default group created. // @Security ApiKeyInHeader || ApiKeyInQuery -// @Tags Validator Dashboards +// @Tags Validator Dashboard // @Accept json // @Produce json // @Param request body handlers.PublicPostValidatorDashboards.request true "`name`: Specify the name of the dashboard.
`network`: Specify the network for the dashboard. Possible options are:" @@ -193,6 +193,16 @@ func (h *HandlerService) PublicPostValidatorDashboards(w http.ResponseWriter, r returnCreated(w, r, response) } +// PublicGetValidatorDashboards godoc +// +// @Description Get overview information for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." +// @Success 200 {object} types.GetValidatorDashboardResponse +// @Failure 400 {object} types.ApiErrorResponse "Bad Request" +// @Router /validator-dashboards/{dashboard_id} [get] func (h *HandlerService) PublicGetValidatorDashboard(w http.ResponseWriter, r *http.Request) { var v validationError dashboardIdParam := mux.Vars(r)["dashboard_id"] @@ -244,6 +254,16 @@ func (h *HandlerService) PublicGetValidatorDashboard(w http.ResponseWriter, r *h returnOk(w, r, response) } +// PublicPutValidatorDashboard godoc +// +// @Description Delete a specified validator dashboard. +// @Security ApiKeyInHeader || ApiKeyInQuery +// @Tags Validator Dashboard Management +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Success 204 "Dashboard deleted successfully." +// @Failure 400 {object} types.ApiErrorResponse "Bad Request" +// @Router /validator-dashboards/{dashboard_id} [delete] func (h *HandlerService) PublicDeleteValidatorDashboard(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId := v.checkPrimaryDashboardId(mux.Vars(r)["dashboard_id"]) @@ -259,6 +279,18 @@ func (h *HandlerService) PublicDeleteValidatorDashboard(w http.ResponseWriter, r returnNoContent(w, r) } +// PublicPutValidatorDashboard godoc +// +// @Description Update the name of a specified validator dashboard. +// @Security ApiKeyInHeader || ApiKeyInQuery +// @Tags Validator Dashboard Management +// @Accept json +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param request body handlers.PublicPutValidatorDashboardName.request true "request" +// @Success 200 {object} types.ApiDataResponse[types.VDBPostReturnData] +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/name [put] func (h *HandlerService) PublicPutValidatorDashboardName(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId := v.checkPrimaryDashboardId(mux.Vars(r)["dashboard_id"]) @@ -286,6 +318,19 @@ func (h *HandlerService) PublicPutValidatorDashboardName(w http.ResponseWriter, returnOk(w, r, response) } +// PublicPostValidatorDashboardGroups godoc +// +// @Description Create a new group in a specified validator dashboard. +// @Security ApiKeyInHeader || ApiKeyInQuery +// @Tags Validator Dashboard Management +// @Accept json +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param request body handlers.PublicPostValidatorDashboardGroups.request true "request" +// @Success 201 {object} types.ApiDataResponse[types.VDBPostCreateGroupData] +// @Failure 400 {object} types.ApiErrorResponse +// @Failure 409 {object} types.ApiErrorResponse "Conflict. The request could not be performed by the server because the authenticated user has already reached their group limit." +// @Router /validator-dashboards/{dashboard_id}/groups [post] func (h *HandlerService) PublicPostValidatorDashboardGroups(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId := v.checkPrimaryDashboardId(mux.Vars(r)["dashboard_id"]) @@ -337,6 +382,19 @@ func (h *HandlerService) PublicPostValidatorDashboardGroups(w http.ResponseWrite returnCreated(w, r, response) } +// PublicGetValidatorDashboardGroups godoc +// +// @Description Update a groups name in a specified validator dashboard. +// @Security ApiKeyInHeader || ApiKeyInQuery +// @Tags Validator Dashboard Management +// @Accept json +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param group_id path string true "The ID of the group." +// @Param request body handlers.PublicPutValidatorDashboardGroups.request true "request" +// @Success 200 {object} types.ApiDataResponse[types.VDBPostCreateGroupData] +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/groups/{group_id} [put] func (h *HandlerService) PublicPutValidatorDashboardGroups(w http.ResponseWriter, r *http.Request) { var v validationError vars := mux.Vars(r) @@ -377,6 +435,18 @@ func (h *HandlerService) PublicPutValidatorDashboardGroups(w http.ResponseWriter returnOk(w, r, response) } +// PublicDeleteValidatorDashboardGroups godoc +// +// @Description Delete a group in a specified validator dashboard. +// @Tags Validator Dashboard Management +// @Security ApiKeyInHeader || ApiKeyInQuery +// @Accept json +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param group_id path string true "The ID of the group." +// @Success 204 "Group deleted successfully." +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/groups/{group_id} [delete] func (h *HandlerService) PublicDeleteValidatorDashboardGroup(w http.ResponseWriter, r *http.Request) { var v validationError vars := mux.Vars(r) @@ -408,6 +478,19 @@ func (h *HandlerService) PublicDeleteValidatorDashboardGroup(w http.ResponseWrit returnNoContent(w, r) } +// PublicGetValidatorDashboardGroups godoc +// +// @Description Add new validators to a specified dashboard or update the group of already-added validators. +// @Security ApiKeyInHeader || ApiKeyInQuery +// @Tags Validator Dashboard Management +// @Accept json +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param request body handlers.PublicPostValidatorDashboardValidators.request true "`group_id`: (optional) Provide a single group id, to which all validators get added to. If omitted, the default group will be used.

To add validators, only one of the following fields can be set:" +// @Success 201 {object} types.ApiDataResponse[[]types.VDBPostValidatorsData] "Returns a list of added validators." +// @Failure 400 {object} types.ApiErrorResponse +// @Failure 409 {object} types.ApiErrorResponse "Conflict. The request could not be performed by the server because the authenticated user has already reached their validator limit." +// @Router /validator-dashboards/{dashboard_id}/validators [post] func (h *HandlerService) PublicPostValidatorDashboardValidators(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId := v.checkPrimaryDashboardId(mux.Vars(r)["dashboard_id"]) @@ -531,6 +614,20 @@ func (h *HandlerService) PublicPostValidatorDashboardValidators(w http.ResponseW returnCreated(w, r, response) } +// PublicGetValidatorDashboardValidators godoc +// +// @Description Get a list of groups in a specified validator dashboard. +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param group_id query string false "The ID of the group." +// @Param cursor query string false "Return data for the given cursor value. Pass the `paging.next_cursor`` value of the previous response to navigate to forward, or pass the `paging.prev_cursor`` value of the previous response to navigate to backward." +// @Param limit query string false "The maximum number of results that may be returned." +// @Param sort query string false "The field you want to sort by. Append with `:desc` for descending order." Enums(index, public_key, balance, status, withdrawal_credentials) +// @Param search query string false "Search for Address, ENS." +// @Success 200 {object} types.GetValidatorDashboardValidatorsResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/groups [get] func (h *HandlerService) PublicGetValidatorDashboardValidators(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId, err := h.handleDashboardId(r.Context(), mux.Vars(r)["dashboard_id"]) @@ -558,19 +655,30 @@ func (h *HandlerService) PublicGetValidatorDashboardValidators(w http.ResponseWr returnOk(w, r, response) } +// PublicDeleteValidatorDashboardValidators godoc +// +// @Description Remove validators from a specified dashboard. +// @Security ApiKeyInHeader || ApiKeyInQuery +// @Tags Validator Dashboard Management +// @Accept json +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param request body handlers.PublicDeleteValidatorDashboardValidators.request true "`validators`: Provide an array of validator indices or public keys that should get removed from the dashboard." +// @Success 204 "Validators removed successfully." +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/validators/bulk-deletions [post] func (h *HandlerService) PublicDeleteValidatorDashboardValidators(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId := v.checkPrimaryDashboardId(mux.Vars(r)["dashboard_id"]) - var indices []uint64 - var publicKeys []string - req := struct { + type request struct { Validators []intOrString `json:"validators"` - }{} + } + var req request if err := v.checkBody(&req, r); err != nil { handleErr(w, r, err) return } - indices, publicKeys = v.checkValidators(req.Validators, false) + indices, publicKeys := v.checkValidators(req.Validators, false) if v.hasErrors() { handleErr(w, r, v) return @@ -589,6 +697,19 @@ func (h *HandlerService) PublicDeleteValidatorDashboardValidators(w http.Respons returnNoContent(w, r) } +// PublicPostValidatorDashboardPublicIds godoc +// +// @Description Create a new public ID for a specified dashboard. This can be used as an ID by other users for non-modyfing (i.e. GET) endpoints only. Currently limited to one per dashboard. +// @Security ApiKeyInHeader || ApiKeyInQuery +// @Tags Validator Dashboard Management +// @Accept json +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param request body handlers.PublicPostValidatorDashboardPublicIds.request true "`name`: Provide a public name for the dashboard
`share_settings`:" +// @Success 201 {object} types.ApiDataResponse[types.VDBPublicId] +// @Failure 400 {object} types.ApiErrorResponse +// @Failure 409 {object} types.ApiErrorResponse "Conflict. The request could not be performed by the server because the authenticated user has already reached their public ID limit." +// @Router /validator-dashboards/{dashboard_id}/public-ids [post] func (h *HandlerService) PublicPostValidatorDashboardPublicIds(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId := v.checkPrimaryDashboardId(mux.Vars(r)["dashboard_id"]) @@ -623,13 +744,26 @@ func (h *HandlerService) PublicPostValidatorDashboardPublicIds(w http.ResponseWr handleErr(w, r, err) return } - response := types.ApiResponse{ - Data: data, + response := types.ApiDataResponse[types.VDBPublicId]{ + Data: *data, } returnCreated(w, r, response) } +// PublicPutValidatorDashboardPublicId godoc +// +// @Description Update a specified public ID for a specified dashboard. +// @Security ApiKeyInHeader || ApiKeyInQuery +// @Tags Validator Dashboard Management +// @Accept json +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param public_id path string true "The ID of the public ID." +// @Param request body handlers.PublicPutValidatorDashboardPublicId.request true "`name`: Provide a public name for the dashboard
`share_settings`:" +// @Success 200 {object} types.ApiDataResponse[types.VDBPublicId] +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/public-ids/{public_id} [put] func (h *HandlerService) PublicPutValidatorDashboardPublicId(w http.ResponseWriter, r *http.Request) { var v validationError vars := mux.Vars(r) @@ -666,13 +800,24 @@ func (h *HandlerService) PublicPutValidatorDashboardPublicId(w http.ResponseWrit handleErr(w, r, err) return } - response := types.ApiResponse{ - Data: data, + response := types.ApiDataResponse[types.VDBPublicId]{ + Data: *data, } returnOk(w, r, response) } +// PublicDeleteValidatorDashboardPublicId godoc +// +// @Description Delete a specified public ID for a specified dashboard. +// @Security ApiKeyInHeader || ApiKeyInQuery +// @Tags Validator Dashboard Management +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param public_id path string true "The ID of the public ID." +// @Success 204 "Public ID deleted successfully." +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/public-ids/{public_id} [delete] func (h *HandlerService) PublicDeleteValidatorDashboardPublicId(w http.ResponseWriter, r *http.Request) { var v validationError vars := mux.Vars(r) @@ -701,12 +846,26 @@ func (h *HandlerService) PublicDeleteValidatorDashboardPublicId(w http.ResponseW returnNoContent(w, r) } +// PublicPutValidatorDashboardArchiving godoc +// +// @Description Archive or unarchive a specified validator dashboard. Archived dashboards cannot be accessed by other endpoints. Archiving happens automatically if the number of dashboards, validators, or groups exceeds the limit allowed by your subscription plan. For example, this might occur if you downgrade your subscription to a lower tier. +// @Security ApiKeyInHeader || ApiKeyInQuery +// @Tags Validator Dashboard Management +// @Accept json +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param request body handlers.PublicPutValidatorDashboardArchiving.request true "request" +// @Success 200 {object} types.ApiDataResponse[types.VDBPostArchivingReturnData] +// @Failure 400 {object} types.ApiErrorResponse +// @Conflict 409 {object} types.ApiErrorResponse "Conflict. The request could not be performed by the server because the authenticated user has already reached their subscription limit." +// @Router /validator-dashboards/{dashboard_id}/archiving [put] func (h *HandlerService) PublicPutValidatorDashboardArchiving(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId := v.checkPrimaryDashboardId(mux.Vars(r)["dashboard_id"]) - req := struct { + type request struct { IsArchived bool `json:"is_archived"` - }{} + } + var req request if err := v.checkBody(&req, r); err != nil { handleErr(w, r, err) return @@ -784,6 +943,16 @@ func (h *HandlerService) PublicPutValidatorDashboardArchiving(w http.ResponseWri returnOk(w, r, response) } +// PublicGetValidatorDashboardSlotViz godoc +// +// @Description Get slot viz information for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param group_ids query string false "Provide a comma separated list of group IDs to filter the results by. If omitted, all groups will be included." +// @Success 200 {object} types.GetValidatorDashboardSlotVizResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/slot-viz [get] func (h *HandlerService) PublicGetValidatorDashboardSlotViz(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId, err := h.handleDashboardId(r.Context(), mux.Vars(r)["dashboard_id"]) @@ -809,6 +978,23 @@ func (h *HandlerService) PublicGetValidatorDashboardSlotViz(w http.ResponseWrite returnOk(w, r, response) } +var summaryAllowedPeriods = []enums.TimePeriod{enums.TimePeriods.AllTime, enums.TimePeriods.Last30d, enums.TimePeriods.Last7d, enums.TimePeriods.Last24h, enums.TimePeriods.Last1h} + +// PublicGetValidatorDashboardSummary godoc +// +// @Description Get summary information for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param period query string true "Time period to get data for." Enums(all_time, last_30d, last_7d, last_24h, last_1h) +// @Param cursor query string false "Return data for the given cursor value. Pass the `paging.next_cursor`` value of the previous response to navigate to forward, or pass the `paging.prev_cursor`` value of the previous response to navigate to backward." +// @Param limit query string false "The maximum number of results that may be returned." +// @Param sort query string false "The field you want to sort by. Append with `:desc` for descending order." Enums(group_id, validators, efficiency, attestations, proposals, reward) +// @Param search query string false "Search for Index, Public Key, Group." +// @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." +// @Success 200 {object} types.GetValidatorDashboardSummaryResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/summary [get] func (h *HandlerService) PublicGetValidatorDashboardSummary(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId, err := h.handleDashboardId(r.Context(), mux.Vars(r)["dashboard_id"]) @@ -823,8 +1009,7 @@ func (h *HandlerService) PublicGetValidatorDashboardSummary(w http.ResponseWrite period := checkEnum[enums.TimePeriod](&v, q.Get("period"), "period") // allowed periods are: all_time, last_30d, last_7d, last_24h, last_1h - allowedPeriods := []enums.TimePeriod{enums.TimePeriods.AllTime, enums.TimePeriods.Last30d, enums.TimePeriods.Last7d, enums.TimePeriods.Last24h, enums.TimePeriods.Last1h} - checkEnumIsAllowed(&v, period, allowedPeriods, "period") + checkEnumIsAllowed(&v, period, summaryAllowedPeriods, "period") if v.hasErrors() { handleErr(w, r, v) return @@ -842,6 +1027,18 @@ func (h *HandlerService) PublicGetValidatorDashboardSummary(w http.ResponseWrite returnOk(w, r, response) } +// PublicGetValidatorDashboardGroupSummary godoc +// +// @Description Get summary information for a specified group in a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param group_id path string true "The ID of the group." +// @Param period query string true "Time period to get data for." Enums(all_time, last_30d, last_7d, last_24h, last_1h) +// @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." +// @Success 200 {object} types.GetValidatorDashboardGroupSummaryResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/groups/{group_id}/summary [get] func (h *HandlerService) PublicGetValidatorDashboardGroupSummary(w http.ResponseWriter, r *http.Request) { var v validationError vars := mux.Vars(r) @@ -859,8 +1056,7 @@ func (h *HandlerService) PublicGetValidatorDashboardGroupSummary(w http.Response groupId := v.checkGroupId(vars["group_id"], forbidEmpty) period := checkEnum[enums.TimePeriod](&v, r.URL.Query().Get("period"), "period") // allowed periods are: all_time, last_30d, last_7d, last_24h, last_1h - allowedPeriods := []enums.TimePeriod{enums.TimePeriods.AllTime, enums.TimePeriods.Last30d, enums.TimePeriods.Last7d, enums.TimePeriods.Last24h, enums.TimePeriods.Last1h} - checkEnumIsAllowed(&v, period, allowedPeriods, "period") + checkEnumIsAllowed(&v, period, summaryAllowedPeriods, "period") if v.hasErrors() { handleErr(w, r, v) return @@ -877,6 +1073,20 @@ func (h *HandlerService) PublicGetValidatorDashboardGroupSummary(w http.Response returnOk(w, r, response) } +// PublicGetValidatorDashboardSummaryChart godoc +// +// @Description Get summary chart data for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param group_ids query string false "Provide a comma separated list of group IDs to filter the results by." +// @Param efficiency_type query string false "Efficiency type to get data for." Enums(all, attestation, sync, proposal) +// @Param aggregation query string false "Aggregation type to get data for." Enums(epoch, hourly, daily, weekly) Default(hourly) +// @Param after_ts query string false "Return data after this timestamp." +// @Param before_ts query string false "Return data before this timestamp." +// @Success 200 {object} types.GetValidatorDashboardSummaryChartResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/summary-chart [get] func (h *HandlerService) PublicGetValidatorDashboardSummaryChart(w http.ResponseWriter, r *http.Request) { var v validationError ctx := r.Context() @@ -916,6 +1126,18 @@ func (h *HandlerService) PublicGetValidatorDashboardSummaryChart(w http.Response returnOk(w, r, response) } +// PublicGetValidatorDashboardSummaryValidators godoc +// +// @Description Get summary information for validators in a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param group_id query string false "The ID of the group." +// @Param duty query string false "Validator duty to get data for." Enums(none, sync, slashed, proposal) Default(none) +// @Param period query string true "Time period to get data for." Enums(all_time, last_30d, last_7d, last_24h, last_1h) +// @Success 200 {object} types.GetValidatorDashboardSummaryValidatorsResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/summary/validators [get] func (h *HandlerService) PublicGetValidatorDashboardSummaryValidators(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId, err := h.handleDashboardId(r.Context(), mux.Vars(r)["dashboard_id"]) @@ -966,6 +1188,20 @@ func (h *HandlerService) PublicGetValidatorDashboardSummaryValidators(w http.Res returnOk(w, r, response) } +// PublicGetValidatorDashboardRewards godoc +// +// @Description Get rewards information for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param cursor query string false "Return data for the given cursor value. Pass the `paging.next_cursor`` value of the previous response to navigate to forward, or pass the `paging.prev_cursor`` value of the previous response to navigate to backward." +// @Param limit query string false "The maximum number of results that may be returned." +// @Param sort query string false "The field you want to sort by. Append with `:desc` for descending order." Enums(epoch) +// @Param search query string false "Search for Epoch, Index, Public Key, Group." +// @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." +// @Success 200 {object} types.GetValidatorDashboardRewardsResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/rewards [get] func (h *HandlerService) PublicGetValidatorDashboardRewards(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId, err := h.handleDashboardId(r.Context(), mux.Vars(r)["dashboard_id"]) @@ -994,6 +1230,18 @@ func (h *HandlerService) PublicGetValidatorDashboardRewards(w http.ResponseWrite returnOk(w, r, response) } +// PublicGetValidatorDashboardGroupRewards godoc +// +// @Description Get rewards information for a specified group in a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param group_id path string true "The ID of the group." +// @Param epoch path string true "The epoch to get data for." +// @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." +// @Success 200 {object} types.GetValidatorDashboardGroupRewardsResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/groups/{group_id}/rewards/{epoch} [get] func (h *HandlerService) PublicGetValidatorDashboardGroupRewards(w http.ResponseWriter, r *http.Request) { var v validationError vars := mux.Vars(r) @@ -1022,6 +1270,16 @@ func (h *HandlerService) PublicGetValidatorDashboardGroupRewards(w http.Response returnOk(w, r, response) } +// PublicGetValidatorDashboardRewardsChart godoc +// +// @Description Get rewards chart data for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." +// @Success 200 {object} types.GetValidatorDashboardRewardsChartResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/rewards-chart [get] func (h *HandlerService) PublicGetValidatorDashboardRewardsChart(w http.ResponseWriter, r *http.Request) { var v validationError vars := mux.Vars(r) @@ -1048,6 +1306,22 @@ func (h *HandlerService) PublicGetValidatorDashboardRewardsChart(w http.Response returnOk(w, r, response) } +// PublicGetValidatorDashboardDuties godoc +// +// @Description Get duties information for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param epoch path string true "The epoch to get data for." +// @Param group_id query string false "The ID of the group." +// @Param cursor query string false "Return data for the given cursor value. Pass the `paging.next_cursor`` value of the previous response to navigate to forward, or pass the `paging.prev_cursor`` value of the previous response to navigate to backward." +// @Param limit query string false "The maximum number of results that may be returned." +// @Param sort query string false "The field you want to sort by. Append with `:desc` for descending order." Enums(validator, reward) +// @Param search query string false "Search for Index, Public Key." +// @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." +// @Success 200 {object} types.GetValidatorDashboardDutiesResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/duties/{epoch} [get] func (h *HandlerService) PublicGetValidatorDashboardDuties(w http.ResponseWriter, r *http.Request) { var v validationError vars := mux.Vars(r) @@ -1079,6 +1353,20 @@ func (h *HandlerService) PublicGetValidatorDashboardDuties(w http.ResponseWriter returnOk(w, r, response) } +// PublicGetValidatorDashboardBlocks godoc +// +// @Description Get blocks information for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param cursor query string false "Return data for the given cursor value. Pass the `paging.next_cursor`` value of the previous response to navigate to forward, or pass the `paging.prev_cursor`` value of the previous response to navigate to backward." +// @Param limit query string false "The maximum number of results that may be returned." +// @Param sort query string false "The field you want to sort by. Append with `:desc` for descending order." Enums(proposer, slot, block, status, reward) +// @Param search query string false "Search for Index, Public Key, Group." +// @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." +// @Success 200 {object} types.GetValidatorDashboardBlocksResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/blocks [get] func (h *HandlerService) PublicGetValidatorDashboardBlocks(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId, err := h.handleDashboardId(r.Context(), mux.Vars(r)["dashboard_id"]) @@ -1107,6 +1395,19 @@ func (h *HandlerService) PublicGetValidatorDashboardBlocks(w http.ResponseWriter returnOk(w, r, response) } +// PublicGetValidatorDashboardHeatmap godoc +// +// @Description Get heatmap information for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param aggregation query string false "Aggregation type to get data for." Enums(epoch, hourly, daily, weekly) Default(hourly) +// @Param after_ts query string false "Return data after this timestamp." +// @Param before_ts query string false "Return data before this timestamp." +// @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." +// @Success 200 {object} types.GetValidatorDashboardHeatmapResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/heatmap [get] func (h *HandlerService) PublicGetValidatorDashboardHeatmap(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId, err := h.handleDashboardId(r.Context(), mux.Vars(r)["dashboard_id"]) @@ -1143,6 +1444,19 @@ func (h *HandlerService) PublicGetValidatorDashboardHeatmap(w http.ResponseWrite returnOk(w, r, response) } +// PublicGetValidatorDashboardGroupHeatmap godoc +// +// @Description Get heatmap information for a specified group in a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param group_id path string true "The ID of the group." +// @Param timestamp path string true "The timestamp to get data for." +// @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." +// @Param aggregation query string false "Aggregation type to get data for." Enums(epoch, hourly, daily, weekly) Default(hourly) +// @Success 200 {object} types.GetValidatorDashboardGroupHeatmapResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/groups/{group_id}/heatmap/{timestamp} [get] func (h *HandlerService) PublicGetValidatorDashboardGroupHeatmap(w http.ResponseWriter, r *http.Request) { var v validationError vars := mux.Vars(r) @@ -1180,6 +1494,17 @@ func (h *HandlerService) PublicGetValidatorDashboardGroupHeatmap(w http.Response returnOk(w, r, response) } +// PublicGetValidatorDashboardExecutionLayerDeposits godoc +// +// @Description Get execution layer deposits information for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param cursor query string false "Return data for the given cursor value. Pass the `paging.next_cursor`` value of the previous response to navigate to forward, or pass the `paging.prev_cursor`` value of the previous response to navigate to backward." +// @Param limit query string false "The maximum number of results that may be returned." +// @Success 200 {object} types.GetValidatorDashboardExecutionLayerDepositsResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/execution-layer-deposits [get] func (h *HandlerService) PublicGetValidatorDashboardExecutionLayerDeposits(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId, err := h.handleDashboardId(r.Context(), mux.Vars(r)["dashboard_id"]) @@ -1205,6 +1530,17 @@ func (h *HandlerService) PublicGetValidatorDashboardExecutionLayerDeposits(w htt returnOk(w, r, response) } +// PublicGetValidatorDashboardConsensusLayerDeposits godoc +// +// @Description Get consensus layer deposits information for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param cursor query string false "Return data for the given cursor value. Pass the `paging.next_cursor`` value of the previous response to navigate to forward, or pass the `paging.prev_cursor`` value of the previous response to navigate to backward." +// @Param limit query string false "The maximum number of results that may be returned." +// @Success 200 {object} types.GetValidatorDashboardConsensusLayerDepositsResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/consensus-layer-deposits [get] func (h *HandlerService) PublicGetValidatorDashboardConsensusLayerDeposits(w http.ResponseWriter, r *http.Request) { var v validationError dashboardId, err := h.handleDashboardId(r.Context(), mux.Vars(r)["dashboard_id"]) @@ -1231,6 +1567,15 @@ func (h *HandlerService) PublicGetValidatorDashboardConsensusLayerDeposits(w htt returnOk(w, r, response) } +// PublicGetValidatorDashboardTotalConsensusLayerDeposits godoc +// +// @Description Get total consensus layer deposits information for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Success 200 {object} types.GetValidatorDashboardTotalConsensusDepositsResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/total-consensus-layer-deposits [get] func (h *HandlerService) PublicGetValidatorDashboardTotalConsensusLayerDeposits(w http.ResponseWriter, r *http.Request) { var err error dashboardId, err := h.handleDashboardId(r.Context(), mux.Vars(r)["dashboard_id"]) @@ -1250,6 +1595,15 @@ func (h *HandlerService) PublicGetValidatorDashboardTotalConsensusLayerDeposits( returnOk(w, r, response) } +// PublicGetValidatorDashboardTotalExecutionLayerDeposits godoc +// +// @Description Get total execution layer deposits information for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Success 200 {object} types.GetValidatorDashboardTotalExecutionDepositsResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/total-execution-layer-deposits [get] func (h *HandlerService) PublicGetValidatorDashboardTotalExecutionLayerDeposits(w http.ResponseWriter, r *http.Request) { var err error dashboardId, err := h.handleDashboardId(r.Context(), mux.Vars(r)["dashboard_id"]) @@ -1269,6 +1623,20 @@ func (h *HandlerService) PublicGetValidatorDashboardTotalExecutionLayerDeposits( returnOk(w, r, response) } +// PublicGetValidatorDashboardWithdrawals godoc +// +// @Description Get withdrawals information for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param cursor query string false "Return data for the given cursor value. Pass the `paging.next_cursor`` value of the previous response to navigate to forward, or pass the `paging.prev_cursor`` value of the previous response to navigate to backward." +// @Param limit query string false "The maximum number of results that may be returned." +// @Param sort query string false "The field you want to sort by. Append with `:desc` for descending order." Enums(epoch, slot, index, recipient, amount) +// @Param search query string false "Search for Index, Public Key, Address." +// @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." +// @Success 200 {object} types.GetValidatorDashboardWithdrawalsResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/withdrawals [get] func (h *HandlerService) PublicGetValidatorDashboardWithdrawals(w http.ResponseWriter, r *http.Request) { var v validationError q := r.URL.Query() @@ -1297,6 +1665,16 @@ func (h *HandlerService) PublicGetValidatorDashboardWithdrawals(w http.ResponseW returnOk(w, r, response) } +// PublicGetValidatorDashboardTotalWithdrawals godoc +// +// @Description Get total withdrawals information for a specified dashboard +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." +// @Success 200 {object} types.GetValidatorDashboardTotalWithdrawalsResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/total-withdrawals [get] func (h *HandlerService) PublicGetValidatorDashboardTotalWithdrawals(w http.ResponseWriter, r *http.Request) { var v validationError q := r.URL.Query() @@ -1324,6 +1702,19 @@ func (h *HandlerService) PublicGetValidatorDashboardTotalWithdrawals(w http.Resp returnOk(w, r, response) } +// PublicGetValidatorDashboardRocketPool godoc +// +// @Description Get an aggregated list of the Rocket Pool nodes details associated with a specified dashboard. +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param cursor query string false "Return data for the given cursor value. Pass the `paging.next_cursor`` value of the previous response to navigate to forward, or pass the `paging.prev_cursor`` value of the previous response to navigate to backward." +// @Param limit query string false "The maximum number of results that may be returned." +// @Param sort query string false "The field you want to sort by. Append with `:desc` for descending order." Enums(node, minipools, collateral, rpl, effective_rpl, rpl_apr, smoothing_pool) +// @Param search query string false "Search for Node address." +// @Success 200 {object} types.GetValidatorDashboardRocketPoolResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/rocket-pool [get] func (h *HandlerService) PublicGetValidatorDashboardRocketPool(w http.ResponseWriter, r *http.Request) { var v validationError q := r.URL.Query() @@ -1351,6 +1742,15 @@ func (h *HandlerService) PublicGetValidatorDashboardRocketPool(w http.ResponseWr returnOk(w, r, response) } +// PublicGetValidatorDashboardTotalRocketPool godoc +// +// @Description Get a summary of all Rocket Pool nodes details associated with a specified dashboard. +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Success 200 {object} types.GetValidatorDashboardTotalRocketPoolResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/total-rocket-pool [get] func (h *HandlerService) PublicGetValidatorDashboardTotalRocketPool(w http.ResponseWriter, r *http.Request) { var v validationError q := r.URL.Query() @@ -1376,6 +1776,16 @@ func (h *HandlerService) PublicGetValidatorDashboardTotalRocketPool(w http.Respo returnOk(w, r, response) } +// PublicGetValidatorDashboardNodeRocketPool godoc +// +// @Description Get details for a specific Rocket Pool node associated with a specified dashboard. +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param node_address path string true "The address of the node." +// @Success 200 {object} types.GetValidatorDashboardNodeRocketPoolResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/rocket-pool/{node_address} [get] func (h *HandlerService) PublicGetValidatorDashboardNodeRocketPool(w http.ResponseWriter, r *http.Request) { var v validationError vars := mux.Vars(r) @@ -1402,6 +1812,20 @@ func (h *HandlerService) PublicGetValidatorDashboardNodeRocketPool(w http.Respon returnOk(w, r, response) } +// PublicGetValidatorDashboardRocketPoolMinipools godoc +// +// @Description Get minipools information for a specified Rocket Pool node associated with a specified dashboard. +// @Tags Validator Dashboard +// @Produce json +// @Param dashboard_id path string true "The ID of the dashboard." +// @Param node_address path string true "The address of the node." +// @Param cursor query string false "Return data for the given cursor value. Pass the `paging.next_cursor`` value of the previous response to navigate to forward, or pass the `paging.prev_cursor`` value of the previous response to navigate to backward." +// @Param limit query string false "The maximum number of results that may be returned." +// @Param sort query string false "The field you want to sort by. Append with `:desc` for descending order. Possible values are TODO." +// @Param search query string false "Search for Index, Node." +// @Success 200 {object} types.GetValidatorDashboardRocketPoolMinipoolsResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /validator-dashboards/{dashboard_id}/rocket-pool/{node_address}/minipools [get] func (h *HandlerService) PublicGetValidatorDashboardRocketPoolMinipools(w http.ResponseWriter, r *http.Request) { var v validationError vars := mux.Vars(r) diff --git a/backend/pkg/api/types/common.go b/backend/pkg/api/types/common.go index e658afa80..2c7253623 100644 --- a/backend/pkg/api/types/common.go +++ b/backend/pkg/api/types/common.go @@ -40,8 +40,8 @@ type Address struct { type LuckItem struct { Percent float64 `json:"percent"` - Expected time.Time `json:"expected"` - Average time.Duration `json:"average"` + Expected time.Time `json:"expected" swaggertype:"string" format:"date-time"` + Average time.Duration `json:"average" swaggertype:"primitive,integer"` } type Luck struct { diff --git a/backend/pkg/api/types/validator_dashboard.go b/backend/pkg/api/types/validator_dashboard.go index 39d5e5d0d..380d035d4 100644 --- a/backend/pkg/api/types/validator_dashboard.go +++ b/backend/pkg/api/types/validator_dashboard.go @@ -27,7 +27,7 @@ type VDBOverviewBalances struct { } type VDBOverviewData struct { - Name string `json:"name,omitempty"` + Name string `json:"name,omitempty" extensions:"x-order=1"` Network uint64 `json:"network"` Groups []VDBOverviewGroup `json:"groups"` Validators VDBOverviewValidators `json:"validators"` @@ -60,7 +60,7 @@ type VDBSummaryValidators struct { } type VDBSummaryTableRow struct { - GroupId int64 `json:"group_id"` + GroupId int64 `json:"group_id" extensions:"x-order=1"` Status VDBSummaryStatus `json:"status"` Validators VDBSummaryValidators `json:"validators"` Efficiency float64 `json:"efficiency"` @@ -116,7 +116,7 @@ type GetValidatorDashboardSummaryChartResponse ApiDataResponse[ChartData[int, fl // ------------------------------------------------------------ // Summary Validators type VDBSummaryValidator struct { - Index uint64 `json:"index"` + Index uint64 `json:"index" extensions:"x-order=1"` DutyObjects []uint64 `json:"duty_objects,omitempty"` } type VDBSummaryValidatorsData struct { @@ -169,7 +169,7 @@ type GetValidatorDashboardRewardsChartResponse ApiDataResponse[ChartData[int, de // Duties Modal type VDBEpochDutiesTableRow struct { - Validator uint64 `json:"validator"` + Validator uint64 `json:"validator" extensions:"x-order=1"` Duties ValidatorHistoryDuties `json:"duties"` } type GetValidatorDashboardDutiesResponse ApiPagingResponse[VDBEpochDutiesTableRow] @@ -177,12 +177,12 @@ type GetValidatorDashboardDutiesResponse ApiPagingResponse[VDBEpochDutiesTableRo // ------------------------------------------------------------ // Blocks Tab type VDBBlocksTableRow struct { - Proposer uint64 `json:"proposer"` - GroupId uint64 `json:"group_id"` - Epoch uint64 `json:"epoch"` - Slot uint64 `json:"slot"` + Proposer uint64 `json:"proposer" extensions:"x-order=1"` + GroupId uint64 `json:"group_id" extensions:"x-order=2"` + Epoch uint64 `json:"epoch" extensions:"x-order=3"` + Slot uint64 `json:"slot" extensions:"x-order=4"` + Block *uint64 `json:"block,omitempty" extensions:"x-order=5"` Status string `json:"status" tstype:"'success' | 'missed' | 'orphaned' | 'scheduled'" faker:"oneof: success, missed, orphaned, scheduled"` - Block *uint64 `json:"block,omitempty"` RewardRecipient *Address `json:"reward_recipient,omitempty"` Reward *ClElValue[decimal.Decimal] `json:"reward,omitempty"` Graffiti *string `json:"graffiti,omitempty"` @@ -198,22 +198,22 @@ type VDBHeatmapEvents struct { Sync bool `json:"sync"` } type VDBHeatmapCell struct { - X int64 `json:"x"` // Timestamp - Y uint64 `json:"y"` // Group ID + X int64 `json:"x" extensions:"x-order=1"` // Timestamp + Y uint64 `json:"y" extensions:"x-order=2"` // Group ID - Value float64 `json:"value"` // Attestaton Rewards + Value float64 `json:"value" extensions:"x-order=3"` // Attestaton Rewards Events *VDBHeatmapEvents `json:"events,omitempty"` } type VDBHeatmap struct { - Timestamps []int64 `json:"timestamps"` // X-Axis Categories (unix timestamp) - GroupIds []uint64 `json:"group_ids"` // Y-Axis Categories - Data []VDBHeatmapCell `json:"data"` + Timestamps []int64 `json:"timestamps" extensions:"x-order=1"` // X-Axis Categories (unix timestamp) + GroupIds []uint64 `json:"group_ids" extensions:"x-order=2"` // Y-Axis Categories + Data []VDBHeatmapCell `json:"data" extensions:"x-order=3"` Aggregation string `json:"aggregation" tstype:"'epoch' | 'hourly' | 'daily' | 'weekly'" faker:"oneof: epoch, hourly, daily, weekly"` } type GetValidatorDashboardHeatmapResponse ApiDataResponse[VDBHeatmap] type VDBHeatmapTooltipData struct { - Timestamp int64 `json:"timestamp"` + Timestamp int64 `json:"timestamp" extensions:"x-order=1"` Proposers StatusCount `json:"proposers"` Syncs uint64 `json:"syncs"` @@ -290,7 +290,7 @@ type GetValidatorDashboardTotalWithdrawalsResponse ApiDataResponse[VDBTotalWithd // ------------------------------------------------------------ // Rocket Pool Tab type VDBRocketPoolTableRow struct { - Node Address `json:"node"` + Node Address `json:"node" extensions:"x-order=1"` Staked struct { Eth decimal.Decimal `json:"eth"` Rpl decimal.Decimal `json:"rpl"`