Skip to content
Merged
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
19 changes: 19 additions & 0 deletions admin/server/reports.go
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ func (s *Server) yamlForManagedReport(opts *adminv1.ReportOptions, ownerUserID s
res.Export.Format = exportFormatYAML(opts.ExportFormat)
res.Export.IncludeHeader = opts.ExportIncludeHeader
res.Export.Limit = uint(opts.ExportLimit)
res.Export.Attach = opts.ExportAttach

res.Notify.Email.Recipients = opts.EmailRecipients
res.Notify.Slack.Channels = opts.SlackChannels
Expand All @@ -598,6 +599,14 @@ func (s *Server) yamlForManagedReport(opts *adminv1.ReportOptions, ownerUserID s
if !res.Annotations.WebOpenMode.Valid() {
return nil, fmt.Errorf("invalid web open mode %q", opts.WebOpenMode)
}
if opts.ExportAttach {
if opts.QueryName == "" { // nolint:staticcheck // backwards compatibility
return nil, fmt.Errorf("export attachments are only supported for query-based reports")
}
if res.Annotations.WebOpenMode != WebOpenModeCreator {
return nil, fmt.Errorf("export attachments are only supported for reports run as the creator")
}
}
if opts.Explore != "" && opts.Canvas != "" {
return nil, fmt.Errorf("cannot set both explore and canvas")
}
Expand Down Expand Up @@ -649,6 +658,7 @@ func (s *Server) yamlForCommittedReport(opts *adminv1.ReportOptions) ([]byte, er
res.Export.Format = exportFormatYAML(opts.ExportFormat)
res.Export.IncludeHeader = opts.ExportIncludeHeader
res.Export.Limit = uint(opts.ExportLimit)
res.Export.Attach = opts.ExportAttach
res.Notify.Email.Recipients = opts.EmailRecipients
res.Notify.Slack.Channels = opts.SlackChannels
res.Notify.Slack.Users = opts.SlackUsers
Expand All @@ -661,6 +671,14 @@ func (s *Server) yamlForCommittedReport(opts *adminv1.ReportOptions) ([]byte, er
if !res.Annotations.WebOpenMode.Valid() {
return nil, fmt.Errorf("invalid web open mode %q", opts.WebOpenMode)
}
if opts.ExportAttach {
if opts.QueryName == "" { // nolint:staticcheck // backwards compatibility
return nil, fmt.Errorf("export attachments are only supported for query-based reports")
}
if res.Annotations.WebOpenMode != WebOpenModeCreator {
return nil, fmt.Errorf("export attachments are only supported for reports run as the creator")
}
}
if opts.Explore != "" && opts.Canvas != "" {
return nil, fmt.Errorf("cannot set both explore and canvas")
}
Expand Down Expand Up @@ -912,6 +930,7 @@ type reportYAML struct {
Format string `yaml:"format"`
IncludeHeader bool `yaml:"include_header"`
Limit uint `yaml:"limit"`
Attach bool `yaml:"attach,omitempty"` // Omitted when false, so runtimes that predate it can parse the YAML
} `yaml:"export"`
Notify struct {
Email struct {
Expand Down
57 changes: 57 additions & 0 deletions admin/server/reports_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package server

import (
"testing"

adminv1 "github.com/rilldata/rill/proto/gen/rill/admin/v1"
runtimev1 "github.com/rilldata/rill/proto/gen/rill/runtime/v1"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)

func TestYAMLForManagedReportExportAttach(t *testing.T) {
s := &Server{}
opts := &adminv1.ReportOptions{
DisplayName: "Weekly report",
RefreshCron: "0 9 * * 1",
QueryName: "MetricsViewAggregation", // nolint:staticcheck // backwards compatibility
QueryArgsJson: `{"metrics_view":"mv1"}`, // nolint:staticcheck // backwards compatibility
ExportFormat: runtimev1.ExportFormat_EXPORT_FORMAT_CSV,
ExportAttach: true,
EmailRecipients: []string{"user_1@example.com"},
Explore: "e1",
WebOpenMode: string(WebOpenModeCreator),
}

// The export is attached for reports run as the creator
data, err := s.yamlForManagedReport(opts, "owner")
require.NoError(t, err)
var res reportYAML
require.NoError(t, yaml.Unmarshal(data, &res))
require.True(t, res.Export.Attach)

// The property is omitted when the export is not attached, so runtimes that predate it can still parse the YAML
opts.ExportAttach = false
data, err = s.yamlForManagedReport(opts, "owner")
require.NoError(t, err)
require.NotContains(t, string(data), "attach")
opts.ExportAttach = true

// Attachments are not supported for reports run as the recipient
opts.WebOpenMode = string(WebOpenModeRecipient)
_, err = s.yamlForManagedReport(opts, "owner")
require.ErrorContains(t, err, "only supported for reports run as the creator")
opts.WebOpenMode = string(WebOpenModeCreator)

// Attachments are not supported for canvas PDF reports
_, err = s.yamlForManagedReport(&adminv1.ReportOptions{
DisplayName: "Canvas report",
RefreshCron: "0 9 * * 1",
ExportFormat: runtimev1.ExportFormat_EXPORT_FORMAT_PDF,
ExportAttach: true,
EmailRecipients: []string{"user_1@example.com"},
Canvas: "c1",
WebOpenMode: string(WebOpenModeCreator),
}, "owner")
require.ErrorContains(t, err, "only supported for query-based reports")
}
8 changes: 8 additions & 0 deletions docs/docs/guide/reports/exports.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ Follow these simple steps to schedule an email report:

![Scheduled](/img/explore/exports/scheduled.png)

### Attaching the File to Emails

Reports that run as the **Creator** can attach the exported CSV, Excel, or Parquet file to the report email, so recipients don't have to download it. Select **Attach file to emails** when you create or edit the report.

- Files larger than 10 MB are not attached. The email says so and still includes the download link.
- Only emails include the attachment. Slack notifications include the download link.
- Attachments are not available for reports that run as the recipient, or for canvas dashboard (PDF) reports.

## Managing Scheduled Reports

Reports are managed from your home screen. To navigate to the report admin page, select the Home button on the top left and the Reports tab from your homepage.
Expand Down
2 changes: 2 additions & 0 deletions docs/docs/reference/project-files/reports.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ _[object]_ - Export configuration for query-based reports

- **`limit`** - _[integer]_ - Maximum number of rows to export

- **`attach`** - _[boolean]_ - If true, attaches the exported file to email notifications. Only supported for query-based reports run as the creator (`web_open_mode` set to `creator`, which is the default). Files larger than 10 MB are not attached; the email links to the download instead.

### `notify`

_[object]_ - Notification configuration for email and Slack delivery
Expand Down
3 changes: 3 additions & 0 deletions proto/gen/rill/admin/v1/admin.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6858,6 +6858,9 @@ definitions:
$ref: '#/definitions/v1ExportFormat'
exportIncludeHeader:
type: boolean
exportAttach:
type: boolean
description: If true, the export is attached to email notifications (only supported for explore reports run as the creator).
emailRecipients:
type: array
items:
Expand Down
Loading
Loading