Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "grafana-github-datasource",
"version": "2.3.0",
"version": "2.3.1",
"private": true,
"description": "The GitHub data source plugin for Grafana lets you to query the GitHub API in Grafana so you can visualize your GitHub repositories and projects.",
"repository": "github:grafana/github-datasource",
Expand Down
52 changes: 46 additions & 6 deletions pkg/github/workflows.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,38 +63,78 @@ func GetWorkflows(ctx context.Context, client models.Client, opts models.ListWor
return nil, fmt.Errorf("listing workflows: opts=%+v %w", opts, err)
}

backend.Logger.Debug("GetWorkflows", "fetched_workflows", len(data.Workflows), "timeField", opts.TimeField, "timeRange", fmt.Sprintf("%v to %v", timeRange.From, timeRange.To))

// If time field is None, return all workflows without filtering
if opts.TimeField == models.WorkflowTimeFieldNone {
backend.Logger.Debug("GetWorkflows", "time_field_none", "returning_all_workflows")
return WorkflowsWrapper(data.Workflows), nil
}

// Otherwise, apply time filtering based on the selected time field
workflows, err := keepWorkflowsInTimeRange(data.Workflows, opts.TimeField, timeRange)
if err != nil {
return nil, fmt.Errorf("filtering workflows by time range: timeField=%d timeRange=%+v %w", opts.TimeField, timeRange, err)
}

backend.Logger.Debug("GetWorkflows", "filtered_workflows", len(workflows))
return WorkflowsWrapper(workflows), nil
}

func keepWorkflowsInTimeRange(workflows []*googlegithub.Workflow, timeField models.WorkflowTimeField, timeRange backend.TimeRange) ([]*googlegithub.Workflow, error) {
// If time range is empty/unset, return all workflows (similar to Tags, Releases, etc.)
if timeRange.From.Unix() <= 0 && timeRange.To.Unix() <= 0 {
backend.Logger.Debug("keepWorkflowsInTimeRange", "time_range_empty", "returning_all_workflows", len(workflows))
return workflows, nil
}

out := make([]*googlegithub.Workflow, 0)
nilCount := 0
excludedCount := 0

for _, workflow := range workflows {
var shouldInclude bool

switch timeField {
case models.WorkflowCreatedAt:
if workflow.CreatedAt.Before(timeRange.From) || workflow.CreatedAt.After(timeRange.To) {
if workflow.CreatedAt == nil {
// If filtering by CreatedAt but CreatedAt is nil, exclude the workflow
nilCount++
continue
}
// Include if CreatedAt is within the time range (inclusive)
createdAtTime := workflow.CreatedAt.Time
shouldInclude = !createdAtTime.Before(timeRange.From) && !createdAtTime.After(timeRange.To)
if !shouldInclude {
excludedCount++
backend.Logger.Debug("keepWorkflowsInTimeRange", "workflow_excluded", *workflow.Name, "createdAt", createdAtTime, "timeRange", fmt.Sprintf("%v to %v", timeRange.From, timeRange.To))
}

case models.WorkflowUpdatedAt:
if workflow.UpdatedAt != nil {
if workflow.UpdatedAt.Before(timeRange.From) || workflow.UpdatedAt.After(timeRange.To) {
continue
}
if workflow.UpdatedAt == nil {
// If filtering by UpdatedAt but UpdatedAt is nil, exclude the workflow
nilCount++
continue
}
// Include if UpdatedAt is within the time range (inclusive)
updatedAtTime := workflow.UpdatedAt.Time
shouldInclude = !updatedAtTime.Before(timeRange.From) && !updatedAtTime.After(timeRange.To)
if !shouldInclude {
excludedCount++
backend.Logger.Debug("keepWorkflowsInTimeRange", "workflow_excluded", *workflow.Name, "updatedAt", updatedAtTime, "timeRange", fmt.Sprintf("%v to %v", timeRange.From, timeRange.To))
}

default:
return nil, backend.DownstreamError(fmt.Errorf("unexpected time field: %d", timeField))
}

out = append(out, workflow)
if shouldInclude {
out = append(out, workflow)
}
}

backend.Logger.Debug("keepWorkflowsInTimeRange", "total_workflows", len(workflows), "included", len(out), "excluded_nil", nilCount, "excluded_out_of_range", excludedCount)

return out, nil
}

Expand Down
4 changes: 3 additions & 1 deletion pkg/models/workflows.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import "time"
type WorkflowTimeField uint32

const (
// WorkflowTimeFieldNone indicates no time filtering should be applied
WorkflowTimeFieldNone WorkflowTimeField = iota
// WorkflowCreatedAt is used when filtering when an workflow was created
WorkflowCreatedAt WorkflowTimeField = iota
WorkflowCreatedAt
// WorkflowUpdatedAt is used when filtering when an Workflow was updated
WorkflowUpdatedAt
)
Expand Down
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export enum IssueTimeField {
}

export enum WorkflowsTimeField {
None,
CreatedAt,
UpdatedAt,
}
Expand Down
6 changes: 3 additions & 3 deletions src/views/QueryEditorWorkflows.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ const timeFieldOptions: Array<SelectableValue<WorkflowsTimeField>> = Object.keys
};
});

const defaultTimeField = 0 as WorkflowsTimeField;
const defaultTimeField = WorkflowsTimeField.None;

const QueryEditorWorkflows = (props: Props) => {
return (
<>
<InlineField
labelWidth={LeftColumnWidth * 2}
label="Time Field"
tooltip="The time field to filter on the time range"
tooltip="Select 'None' to return all workflows, or choose a time field to filter by the dashboard time range"
>
<Select
width={RightColumnWidth}
options={timeFieldOptions}
value={props.timeField || defaultTimeField}
value={props.timeField !== undefined ? props.timeField : defaultTimeField}
onChange={(opt) => {
props.onChange({
...props,
Expand Down