diff --git a/.betterer.results b/.betterer.results
index 7ef79733a91..10a8dd7e282 100644
--- a/.betterer.results
+++ b/.betterer.results
@@ -3420,13 +3420,15 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "9"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "10"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "11"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "12"],
+ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "12"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "13"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "14"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "15"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "16"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "17"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "18"]
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "18"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "19"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "20"]
],
"public/app/features/dashboard-scene/saving/shared.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"],
@@ -5834,21 +5836,16 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "23"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "24"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "25"],
- [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "26"],
- [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "27"],
- [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "28"],
- [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "29"],
- [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "30"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "26"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "27"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "28"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "29"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "30"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "31"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "32"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "33"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "34"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "35"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "36"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "37"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "38"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "39"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "40"]
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "35"]
],
"public/app/features/provisioning/DeleteRepositoryButton.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"],
diff --git a/pkg/apis/provisioning/v0alpha1/types.go b/pkg/apis/provisioning/v0alpha1/types.go
index a85b96d038d..b15abba20e3 100644
--- a/pkg/apis/provisioning/v0alpha1/types.go
+++ b/pkg/apis/provisioning/v0alpha1/types.go
@@ -74,8 +74,8 @@ type RepositorySpec struct {
// Repository description
Description string `json:"description,omitempty"`
- // Edit options within the repository
- Editing EditingOptions `json:"editing"`
+ // ReadOnly repository does not allow any write commands
+ ReadOnly bool `json:"readOnly"`
// Sync settings -- how values are pulled from the repository into grafana
Sync SyncOptions `json:"sync"`
@@ -130,15 +130,6 @@ type SyncOptions struct {
IntervalSeconds int64 `json:"intervalSeconds,omitempty"`
}
-type EditingOptions struct {
- // End users can create new files in the remote file system
- Create bool `json:"create"`
- // End users can update existing files in the remote file system
- Update bool `json:"update"`
- // End users can delete existing files in the remote file system
- Delete bool `json:"delete"`
-}
-
// The status of a Repository.
// This is expected never to be created by a kubectl call or similar, and is expected to rarely (if ever) be edited manually.
// As such, it is also a little less well structured than the spec, such as conditional-but-ever-present fields.
diff --git a/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go b/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go
index 68ef293def5..b3734c25d79 100644
--- a/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go
@@ -27,22 +27,6 @@ func (in *Author) DeepCopy() *Author {
return out
}
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *EditingOptions) DeepCopyInto(out *EditingOptions) {
- *out = *in
- return
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EditingOptions.
-func (in *EditingOptions) DeepCopy() *EditingOptions {
- if in == nil {
- return nil
- }
- out := new(EditingOptions)
- in.DeepCopyInto(out)
- return out
-}
-
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExportJobOptions) DeepCopyInto(out *ExportJobOptions) {
*out = *in
@@ -475,7 +459,6 @@ func (in *RepositoryList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RepositorySpec) DeepCopyInto(out *RepositorySpec) {
*out = *in
- out.Editing = in.Editing
out.Sync = in.Sync
if in.Local != nil {
in, out := &in.Local, &out.Local
diff --git a/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go b/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go
index 7a19f4b4643..a163fe1e78c 100644
--- a/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go
+++ b/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go
@@ -15,7 +15,6 @@ import (
func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
return map[string]common.OpenAPIDefinition{
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.Author": schema_pkg_apis_provisioning_v0alpha1_Author(ref),
- "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.EditingOptions": schema_pkg_apis_provisioning_v0alpha1_EditingOptions(ref),
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ExportJobOptions": schema_pkg_apis_provisioning_v0alpha1_ExportJobOptions(ref),
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.FileItem": schema_pkg_apis_provisioning_v0alpha1_FileItem(ref),
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.FileList": schema_pkg_apis_provisioning_v0alpha1_FileList(ref),
@@ -86,43 +85,6 @@ func schema_pkg_apis_provisioning_v0alpha1_Author(ref common.ReferenceCallback)
}
}
-func schema_pkg_apis_provisioning_v0alpha1_EditingOptions(ref common.ReferenceCallback) common.OpenAPIDefinition {
- return common.OpenAPIDefinition{
- Schema: spec.Schema{
- SchemaProps: spec.SchemaProps{
- Type: []string{"object"},
- Properties: map[string]spec.Schema{
- "create": {
- SchemaProps: spec.SchemaProps{
- Description: "End users can create new files in the remote file system",
- Default: false,
- Type: []string{"boolean"},
- Format: "",
- },
- },
- "update": {
- SchemaProps: spec.SchemaProps{
- Description: "End users can update existing files in the remote file system",
- Default: false,
- Type: []string{"boolean"},
- Format: "",
- },
- },
- "delete": {
- SchemaProps: spec.SchemaProps{
- Description: "End users can delete existing files in the remote file system",
- Default: false,
- Type: []string{"boolean"},
- Format: "",
- },
- },
- },
- Required: []string{"create", "update", "delete"},
- },
- },
- }
-}
-
func schema_pkg_apis_provisioning_v0alpha1_ExportJobOptions(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
@@ -974,11 +936,12 @@ func schema_pkg_apis_provisioning_v0alpha1_RepositorySpec(ref common.ReferenceCa
Format: "",
},
},
- "editing": {
+ "readOnly": {
SchemaProps: spec.SchemaProps{
- Description: "Edit options within the repository",
- Default: map[string]interface{}{},
- Ref: ref("github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.EditingOptions"),
+ Description: "ReadOnly repository does not allow any write commands",
+ Default: false,
+ Type: []string{"boolean"},
+ Format: "",
},
},
"sync": {
@@ -1016,11 +979,11 @@ func schema_pkg_apis_provisioning_v0alpha1_RepositorySpec(ref common.ReferenceCa
},
},
},
- Required: []string{"title", "editing", "sync", "type"},
+ Required: []string{"title", "readOnly", "sync", "type"},
},
},
Dependencies: []string{
- "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.EditingOptions", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.GitHubRepositoryConfig", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.LocalRepositoryConfig", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.S3RepositoryConfig", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.SyncOptions"},
+ "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.GitHubRepositoryConfig", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.LocalRepositoryConfig", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.S3RepositoryConfig", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.SyncOptions"},
}
}
diff --git a/pkg/generated/applyconfiguration/provisioning/v0alpha1/editingoptions.go b/pkg/generated/applyconfiguration/provisioning/v0alpha1/editingoptions.go
deleted file mode 100644
index 9807b8fa4d8..00000000000
--- a/pkg/generated/applyconfiguration/provisioning/v0alpha1/editingoptions.go
+++ /dev/null
@@ -1,43 +0,0 @@
-// SPDX-License-Identifier: AGPL-3.0-only
-
-// Code generated by applyconfiguration-gen. DO NOT EDIT.
-
-package v0alpha1
-
-// EditingOptionsApplyConfiguration represents a declarative configuration of the EditingOptions type for use
-// with apply.
-type EditingOptionsApplyConfiguration struct {
- Create *bool `json:"create,omitempty"`
- Update *bool `json:"update,omitempty"`
- Delete *bool `json:"delete,omitempty"`
-}
-
-// EditingOptionsApplyConfiguration constructs a declarative configuration of the EditingOptions type for use with
-// apply.
-func EditingOptions() *EditingOptionsApplyConfiguration {
- return &EditingOptionsApplyConfiguration{}
-}
-
-// WithCreate sets the Create field in the declarative configuration to the given value
-// and returns the receiver, so that objects can be built by chaining "With" function invocations.
-// If called multiple times, the Create field is set to the value of the last call.
-func (b *EditingOptionsApplyConfiguration) WithCreate(value bool) *EditingOptionsApplyConfiguration {
- b.Create = &value
- return b
-}
-
-// WithUpdate sets the Update field in the declarative configuration to the given value
-// and returns the receiver, so that objects can be built by chaining "With" function invocations.
-// If called multiple times, the Update field is set to the value of the last call.
-func (b *EditingOptionsApplyConfiguration) WithUpdate(value bool) *EditingOptionsApplyConfiguration {
- b.Update = &value
- return b
-}
-
-// WithDelete sets the Delete field in the declarative configuration to the given value
-// and returns the receiver, so that objects can be built by chaining "With" function invocations.
-// If called multiple times, the Delete field is set to the value of the last call.
-func (b *EditingOptionsApplyConfiguration) WithDelete(value bool) *EditingOptionsApplyConfiguration {
- b.Delete = &value
- return b
-}
diff --git a/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go b/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go
index a62be2803f2..8cdedec2731 100644
--- a/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go
+++ b/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go
@@ -13,7 +13,7 @@ import (
type RepositorySpecApplyConfiguration struct {
Title *string `json:"title,omitempty"`
Description *string `json:"description,omitempty"`
- Editing *EditingOptionsApplyConfiguration `json:"editing,omitempty"`
+ ReadOnly *bool `json:"readOnly,omitempty"`
Sync *SyncOptionsApplyConfiguration `json:"sync,omitempty"`
Type *provisioningv0alpha1.RepositoryType `json:"type,omitempty"`
Local *LocalRepositoryConfigApplyConfiguration `json:"local,omitempty"`
@@ -43,11 +43,11 @@ func (b *RepositorySpecApplyConfiguration) WithDescription(value string) *Reposi
return b
}
-// WithEditing sets the Editing field in the declarative configuration to the given value
+// WithReadOnly sets the ReadOnly field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
-// If called multiple times, the Editing field is set to the value of the last call.
-func (b *RepositorySpecApplyConfiguration) WithEditing(value *EditingOptionsApplyConfiguration) *RepositorySpecApplyConfiguration {
- b.Editing = value
+// If called multiple times, the ReadOnly field is set to the value of the last call.
+func (b *RepositorySpecApplyConfiguration) WithReadOnly(value bool) *RepositorySpecApplyConfiguration {
+ b.ReadOnly = &value
return b
}
diff --git a/pkg/generated/applyconfiguration/utils.go b/pkg/generated/applyconfiguration/utils.go
index 2042aac7eb1..bae4891ada9 100644
--- a/pkg/generated/applyconfiguration/utils.go
+++ b/pkg/generated/applyconfiguration/utils.go
@@ -20,8 +20,6 @@ import (
func ForKind(kind schema.GroupVersionKind) interface{} {
switch kind {
// Group=provisioning.grafana.app, Version=v0alpha1
- case v0alpha1.SchemeGroupVersion.WithKind("EditingOptions"):
- return &provisioningv0alpha1.EditingOptionsApplyConfiguration{}
case v0alpha1.SchemeGroupVersion.WithKind("GitHubRepositoryConfig"):
return &provisioningv0alpha1.GitHubRepositoryConfigApplyConfiguration{}
case v0alpha1.SchemeGroupVersion.WithKind("HealthStatus"):
diff --git a/pkg/registry/apis/provisioning/export.go b/pkg/registry/apis/provisioning/export.go
index 94c39723e84..14c3d7c3fbc 100644
--- a/pkg/registry/apis/provisioning/export.go
+++ b/pkg/registry/apis/provisioning/export.go
@@ -52,6 +52,12 @@ func (c *exportConnector) Connect(
return nil, err
}
cfg := repo.Config()
+ if !cfg.Spec.ReadOnly {
+ return nil, &apierrors.StatusError{ErrStatus: v1.Status{
+ Code: http.StatusPreconditionFailed,
+ Message: "Repository is read only",
+ }}
+ }
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
options := &provisioning.ExportJobOptions{}
diff --git a/pkg/registry/apis/provisioning/files.go b/pkg/registry/apis/provisioning/files.go
index 1edde27db2f..f28d1fad3be 100644
--- a/pkg/registry/apis/provisioning/files.go
+++ b/pkg/registry/apis/provisioning/files.go
@@ -183,11 +183,9 @@ func (s *filesConnector) doRead(ctx context.Context, repo repository.Repository,
}
func (s *filesConnector) doWrite(ctx context.Context, update bool, repo repository.Repository, path string, ref string, message string, req *http.Request) (*provisioning.ResourceWrapper, error) {
- settings := repo.Config().Spec.Editing
- if update && !settings.Update {
- return nil, apierrors.NewForbidden(provisioning.RepositoryResourceInfo.GroupResource(), "updating files not enabled", nil)
- } else if !settings.Create {
- return nil, apierrors.NewForbidden(provisioning.RepositoryResourceInfo.GroupResource(), "creating files not enabled", nil)
+ if repo.Config().Spec.ReadOnly {
+ return nil, apierrors.NewForbidden(provisioning.RepositoryResourceInfo.GroupResource(),
+ "this repository is read only", nil)
}
defer func() { _ = req.Body.Close() }()
@@ -270,9 +268,9 @@ func (s *filesConnector) doWrite(ctx context.Context, update bool, repo reposito
}
func (s *filesConnector) doDelete(ctx context.Context, repo repository.Repository, path string, ref string, message string) (*provisioning.ResourceWrapper, error) {
- settings := repo.Config().Spec.Editing
- if !settings.Delete {
- return nil, apierrors.NewForbidden(provisioning.RepositoryResourceInfo.GroupResource(), "deleting is not supported", nil)
+ if repo.Config().Spec.ReadOnly {
+ return nil, apierrors.NewForbidden(provisioning.RepositoryResourceInfo.GroupResource(),
+ "this repository is read only", nil)
}
err := repo.Delete(ctx, path, ref, message)
diff --git a/pkg/registry/apis/provisioning/jobs/worker.go b/pkg/registry/apis/provisioning/jobs/worker.go
index 5d61c2da2e5..e8e2734d741 100644
--- a/pkg/registry/apis/provisioning/jobs/worker.go
+++ b/pkg/registry/apis/provisioning/jobs/worker.go
@@ -131,6 +131,13 @@ func (g *JobWorker) Process(ctx context.Context, job provisioning.Job, progress
}, nil
}
+ if repo.Config().Spec.ReadOnly {
+ return &provisioning.JobStatus{
+ State: provisioning.JobStateError,
+ Errors: []string{"Exporting to a read only repository is not supported"},
+ }, nil
+ }
+
var exporter Exporter
// Test for now... so we have something with long spinners for UI testing!!!
diff --git a/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json b/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json
index 565bc45841a..10a8b667905 100644
--- a/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json
+++ b/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json
@@ -2653,31 +2653,6 @@
"additionalProperties": true,
"x-kubernetes-preserve-unknown-fields": true
},
- "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.EditingOptions": {
- "type": "object",
- "required": [
- "create",
- "update",
- "delete"
- ],
- "properties": {
- "create": {
- "description": "End users can create new files in the remote file system",
- "type": "boolean",
- "default": false
- },
- "delete": {
- "description": "End users can delete existing files in the remote file system",
- "type": "boolean",
- "default": false
- },
- "update": {
- "description": "End users can update existing files in the remote file system",
- "type": "boolean",
- "default": false
- }
- }
- },
"com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.ExportJobOptions": {
"type": "object",
"properties": {
@@ -3140,7 +3115,7 @@
"type": "object",
"required": [
"title",
- "editing",
+ "readOnly",
"sync",
"type"
],
@@ -3149,15 +3124,6 @@
"description": "Repository description",
"type": "string"
},
- "editing": {
- "description": "Edit options within the repository",
- "default": {},
- "allOf": [
- {
- "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.EditingOptions"
- }
- ]
- },
"github": {
"description": "The repository on GitHub. Mutually exclusive with local | s3 | github.",
"allOf": [
@@ -3174,6 +3140,11 @@
}
]
},
+ "readOnly": {
+ "description": "ReadOnly repository does not allow any write commands",
+ "type": "boolean",
+ "default": false
+ },
"s3": {
"description": "The repository in an S3 bucket. Mutually exclusive with local | s3 | github.",
"allOf": [
diff --git a/public/app/features/dashboard-scene/saving/provisioned/SaveProvisionedDashboard.tsx b/public/app/features/dashboard-scene/saving/provisioned/SaveProvisionedDashboard.tsx
index 780ac08397b..49a9ab68165 100644
--- a/public/app/features/dashboard-scene/saving/provisioned/SaveProvisionedDashboard.tsx
+++ b/public/app/features/dashboard-scene/saving/provisioned/SaveProvisionedDashboard.tsx
@@ -111,6 +111,12 @@ export function SaveProvisionedDashboard({ drawer, changeInfo, dashboard }: Prop
return (