Compare commits

...

17 Commits

Author SHA1 Message Date
Hugo Häggmark
3c8c2b338e chore: yarn generate-apis 2026-01-08 11:14:17 +01:00
Hugo Häggmark
1cc4826e8b chore: change make name 2026-01-08 11:08:08 +01:00
Hugo Häggmark
6b47cffc17 Merge remote-tracking branch 'origin/main' into hugoh/openapi-specs 2026-01-08 11:07:45 +01:00
renovate-sh-app[bot]
79f2016a66 chore(deps): update dependency @openfeature/ofrep-web-provider to v0.3.5 (#115963)
| datasource | package                         | from  | to    |
| ---------- | ------------------------------- | ----- | ----- |
| npm        | @openfeature/ofrep-web-provider | 0.3.3 | 0.3.5 |

Signed-off-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com>
Co-authored-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com>
2026-01-08 09:49:04 +00:00
renovate-sh-app[bot]
7858dcb9c1 chore(deps): update dependency @openfeature/web-sdk to v1.7.2 (#115964)
| datasource | package              | from  | to    |
| ---------- | -------------------- | ----- | ----- |
| npm        | @openfeature/web-sdk | 1.7.1 | 1.7.2 |

Signed-off-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com>
Co-authored-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com>
2026-01-08 09:48:41 +00:00
Hugo Häggmark
03563f418c chore: update pre and postpack scripts 2026-01-08 10:35:53 +01:00
Joey
27eb488a96 Chore: Remove Drilldown Investigations (#115471)
* Remove investigations app

* Remove other files

* Remove feature toggle

* Update codeowners

* make update-workspace

* Regen files with make gen-go gen-feature-toggles
2026-01-08 09:28:20 +00:00
Hugo Häggmark
c3f03034df chore: fixes in package.json 2026-01-08 10:15:35 +01:00
Hugo Häggmark
4c8cc4b270 chore: add custom cleanup of files 2026-01-05 07:47:38 +01:00
Hugo Häggmark
34635cedc5 chore: trying to free up space 2026-01-05 07:30:07 +01:00
Hugo Häggmark
46f5474aca chore: merge with main 2026-01-05 06:39:43 +01:00
Hugo Häggmark
5589adae18 Merge remote-tracking branch 'origin/main' into hugoh/openapi-specs 2026-01-05 06:24:12 +01:00
Hugo Häggmark
33c430b2a7 chore: run yarn generate-apis 2025-12-09 08:24:26 +01:00
Hugo Häggmark
0094382121 Merge remote-tracking branch 'origin/main' into hugoh/openapi-specs 2025-12-09 08:06:01 +01:00
Hugo Häggmark
979b04c3e7 chore: run yarn generate-apis 2025-11-28 11:42:11 +01:00
Tom Ratcliffe
9ce9e49da3 Add attributes to mark specs as generated files 2025-11-28 11:22:59 +01:00
Hugo Häggmark
95da237f51 chore: grafana/openapi package 2025-11-28 11:07:19 +01:00
93 changed files with 82978 additions and 4108 deletions

5
.github/CODEOWNERS vendored
View File

@@ -94,7 +94,6 @@
/apps/shorturl/ @grafana/sharing-squad
/apps/secret/ @grafana/grafana-operator-experience-squad
/apps/scope/ @grafana/grafana-operator-experience-squad
/apps/investigations/ @fcjack @matryer @svennergr
/apps/advisor/ @grafana/plugins-platform-backend
/apps/iam/ @grafana/access-squad
/apps/sdk.mk @grafana/grafana-app-platform-squad
@@ -755,6 +754,10 @@ i18next.config.ts @grafana/grafana-frontend-platform
/packages/grafana-api-clients/src/clients/rtkq/provisioning/ @grafana/grafana-git-ui-sync-team
/packages/grafana-api-clients/src/clients/rtkq/shorturl/ @grafana/sharing-squad
# @grafana/openapi
/packages/grafana-openapi/ @grafana/plugins-platform-frontend @grafana/grafana-search-navigate-organise @grafana/grafana-frontend-platform
# root files, mostly frontend
/.browserslistrc @grafana/frontend-ops
/package.json @grafana/frontend-ops

View File

@@ -19,7 +19,6 @@ updates:
- "/apps/dashboard"
- "/apps/folder"
- "/apps/iam"
- "/apps/investigations"
- "/apps/playlist"
- "/apps/plugins"
- "/apps/preferences"

View File

@@ -152,6 +152,43 @@ jobs:
echo "${uncommited_error_message}"
exit 1
fi
lint-frontend-openapi:
# Run this workflow for OSS only
permissions:
contents: read
id-token: write
name: Verify OpenAPI specs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'yarn'
cache-dependency-path: 'yarn.lock'
- run: yarn install --immutable --check-cache
- name: Free up disk space
run: |
sudo rm -rf /usr/local/lib/android || true
sudo rm -rf /usr/share/dotnet || true
sudo rm -rf /opt/ghc || true
sudo rm -rf /usr/local/.ghcup || true
- name: Generate OpenAPI specs
run: |
extract_error_message='ERROR! OpenAPI generation failed!'
yarn generate:openapi || (echo "${extract_error_message}" && false)
- name: Verify generated specs
run: |
git add -N .
uncommited_error_message="ERROR! OpenAPI generation has not been committed. Please run 'yarn generate:openapi', commit the changes and push again."
file_diff="$(git diff --name-only ':!conf')"
if [ -n "$file_diff" ]; then
echo "$file_diff"
echo "${uncommited_error_message}"
exit 1
fi
lint-frontend-api-clients-enterprise:
permissions:
contents: read

View File

@@ -67,14 +67,6 @@ linters:
deny:
- pkg: github.com/grafana/grafana/pkg
desc: apiserver is not allowed to import grafana core
apps-investigation:
list-mode: lax
files:
- ./apps/investigations/*
- ./apps/investigations/**/*
deny:
- pkg: github.com/grafana/grafana/pkg
desc: apps/investigations is not allowed to import grafana core
apps-playlist:
list-mode: lax
files:

View File

@@ -103,7 +103,6 @@ COPY apps/collections apps/collections
COPY apps/provisioning apps/provisioning
COPY apps/secret apps/secret
COPY apps/scope apps/scope
COPY apps/investigations apps/investigations
COPY apps/logsdrilldown apps/logsdrilldown
COPY apps/advisor apps/advisor
COPY apps/dashboard apps/dashboard

View File

@@ -127,6 +127,11 @@ OAPI_SPEC_TARGET = public/openapi3.json
openapi3-gen: swagger-gen ## Generates OpenApi 3 specs from the Swagger 2 already generated
$(GO) run $(GO_RACE_FLAG) scripts/openapi3/openapi3conv.go $(MERGED_SPEC_TARGET) $(OAPI_SPEC_TARGET)
.PHONY: generate-openapi
generate-openapi: openapi3-gen
$(GO) test ./pkg/tests/apis || true
yarn workspace @grafana/openapi process-specs
##@ Internationalisation
.PHONY: i18n-extract-enterprise
ENTERPRISE_FE_EXT_FILE = public/app/extensions/index.ts

View File

@@ -24,8 +24,6 @@ replace github.com/grafana/grafana/apps/alerting/historian => ../alerting/histor
replace github.com/grafana/grafana/apps/correlations => ../correlations
replace github.com/grafana/grafana/apps/investigations => ../investigations
replace github.com/grafana/grafana/apps/logsdrilldown => ../logsdrilldown
replace github.com/grafana/grafana/apps/playlist => ../playlist

View File

@@ -1,10 +0,0 @@
include ../sdk.mk
.PHONY: generate # Run Grafana App SDK code generation
generate: install-app-sdk update-app-sdk
@$(APP_SDK_BIN) generate \
--source=./kinds/ \
--gogenpath=./pkg/apis \
--grouping=group \
--genoperatorstate=false \
--defencoding=none

View File

@@ -1,152 +0,0 @@
[
{
"id": "896312ce-65b0-4b50-ade1-e7f04fa22c66",
"title": "Thursday morning investigation",
"hasCustomName": false,
"isFavorite": false,
"collectables": [
{
"origin": "Explore Logs",
"type": "timeseries",
"queries": [
{
"refId": "LABEL_BREAKDOWN_VALUES",
"queryType": "range",
"editorMode": "code",
"supportingQueryType": "grafana-lokiexplore-app",
"legendFormat": "{{detected_level}}",
"expr": "sum(count_over_time({service_name=\"web_app_1\"} | detected_level != \"\"[$__auto])) by (detected_level)"
}
],
"timeRange": {
"to": "2025-02-13T11:31:20.536Z",
"from": "2025-02-13T11:16:20.536Z",
"raw": {
"from": "now-15m",
"to": "now"
}
},
"datasource": {
"uid": "fe9k7u07b1a0wc"
},
"url": "http://localhost:3000/a/grafana-lokiexplore-app/explore/service/web_app_1/labels?patterns=%5B%5D&from=now-15m&to=now&var-ds=fe9k7u07b1a0wc&var-filters=service_name%7C%3D%7Cweb_app_1&var-fields=&var-levels=&var-metadata=&var-patterns=&var-lineFilterV2=&var-lineFilters=&urlColumns=%5B%5D&visualizationType=%22logs%22&displayedFields=%5B%5D&timezone=browser&var-all-fields=&var-labelBy=$__all",
"id": "LABEL_BREAKDOWN_VALUES_detected_level",
"title": "detected_level",
"logoPath": "public/plugins/grafana-lokiexplore-app/img/img/logo.svg",
"createdAt": "2025-02-13T11:31:23.637Z"
}
],
"createdAt": "2025-02-13T11:31:23.636Z",
"updatedAt": "2025-02-13T11:31:23.637Z",
"viewMode": {
"mode": "compact",
"showComments": true,
"showTooltips": false
}
},
{
"id": "e9cf1958-d0ed-46b7-b597-9052c7648656",
"title": "Thursday morning investigation",
"hasCustomName": false,
"isFavorite": false,
"collectables": [
{
"origin": "Explore Logs",
"type": "timeseries",
"queries": [
{
"refId": "LABEL_BREAKDOWN_VALUES",
"queryType": "range",
"editorMode": "code",
"supportingQueryType": "grafana-lokiexplore-app",
"legendFormat": "{{detected_level}}",
"expr": "sum(count_over_time({service_name=\"web_app_1\"} | detected_level != \"\"[$__auto])) by (detected_level)"
}
],
"timeRange": {
"to": "2025-02-13T11:31:20.536Z",
"from": "2025-02-13T11:16:20.536Z",
"raw": {
"from": "now-15m",
"to": "now"
}
},
"datasource": {
"uid": "fe9k7u07b1a0wc"
},
"url": "http://localhost:3000/a/grafana-lokiexplore-app/explore/service/web_app_1/labels?patterns=%5B%5D&from=now-15m&to=now&var-ds=fe9k7u07b1a0wc&var-filters=service_name%7C%3D%7Cweb_app_1&var-fields=&var-levels=&var-metadata=&var-patterns=&var-lineFilterV2=&var-lineFilters=&urlColumns=%5B%5D&visualizationType=%22logs%22&displayedFields=%5B%5D&timezone=browser&var-all-fields=&var-labelBy=$__all",
"id": "LABEL_BREAKDOWN_VALUES_detected_level",
"title": "detected_level",
"logoPath": "public/plugins/grafana-lokiexplore-app/img/img/logo.svg",
"createdAt": "2025-02-13T11:31:23.638Z"
},
{
"origin": "Explore Logs",
"type": "timeseries",
"queries": [
{
"refId": "LABEL_BREAKDOWN_VALUES",
"queryType": "range",
"editorMode": "code",
"supportingQueryType": "grafana-lokiexplore-app",
"legendFormat": "{{service_name}}",
"expr": "sum(count_over_time({service_name=\"web_app_1\",service_name != \"\"} [$__auto])) by (service_name)"
}
],
"timeRange": {
"to": "2025-02-13T11:31:20.536Z",
"from": "2025-02-13T11:16:20.536Z",
"raw": {
"from": "now-15m",
"to": "now"
}
},
"datasource": {
"uid": "fe9k7u07b1a0wc"
},
"url": "http://localhost:3000/a/grafana-lokiexplore-app/explore/service/web_app_1/labels?patterns=%5B%5D&from=now-15m&to=now&var-ds=fe9k7u07b1a0wc&var-filters=service_name%7C%3D%7Cweb_app_1&var-fields=&var-levels=&var-metadata=&var-patterns=&var-lineFilterV2=&var-lineFilters=&urlColumns=%5B%5D&visualizationType=%22logs%22&displayedFields=%5B%5D&timezone=browser&var-all-fields=&var-labelBy=$__all",
"id": "LABEL_BREAKDOWN_VALUES_service_name",
"title": "service_name",
"logoPath": "public/plugins/grafana-lokiexplore-app/img/img/logo.svg",
"createdAt": "2025-02-13T11:31:41.507Z"
},
{
"origin": "Explore Logs",
"type": "timeseries",
"queries": [
{
"refId": "LABEL_BREAKDOWN_VALUES",
"queryType": "range",
"editorMode": "code",
"supportingQueryType": "grafana-lokiexplore-app",
"legendFormat": "{{service}}",
"expr": "sum(count_over_time({service_name=\"web_app_1\",service != \"\"} [$__auto])) by (service)"
}
],
"timeRange": {
"to": "2025-02-13T11:31:20.536Z",
"from": "2025-02-13T11:16:20.536Z",
"raw": {
"from": "now-15m",
"to": "now"
}
},
"datasource": {
"uid": "fe9k7u07b1a0wc"
},
"url": "http://localhost:3000/a/grafana-lokiexplore-app/explore/service/web_app_1/labels?patterns=%5B%5D&from=now-15m&to=now&var-ds=fe9k7u07b1a0wc&var-filters=service_name%7C%3D%7Cweb_app_1&var-fields=&var-levels=&var-metadata=&var-patterns=&var-lineFilterV2=&var-lineFilters=&urlColumns=%5B%5D&visualizationType=%22logs%22&displayedFields=%5B%5D&timezone=browser&var-all-fields=&var-labelBy=$__all",
"id": "LABEL_BREAKDOWN_VALUES_service",
"title": "service",
"logoPath": "public/plugins/grafana-lokiexplore-app/img/img/logo.svg",
"createdAt": "2025-02-13T11:31:43.698Z"
}
],
"createdAt": "2025-02-13T11:31:23.637Z",
"updatedAt": "2025-02-13T11:31:43.698Z",
"viewMode": {
"mode": "compact",
"showComments": true,
"showTooltips": false
}
}
]

View File

@@ -1,102 +0,0 @@
module github.com/grafana/grafana/apps/investigations
go 1.25.5
require (
github.com/grafana/grafana-app-sdk v0.48.7
k8s.io/apimachinery v0.34.3
k8s.io/klog/v2 v2.130.1
k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/getkin/kin-openapi v0.133.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.22.4 // indirect
github.com/go-openapi/jsonreference v0.21.4 // indirect
github.com/go-openapi/swag v0.25.4 // indirect
github.com/go-openapi/swag/cmdutils v0.25.4 // indirect
github.com/go-openapi/swag/conv v0.25.4 // indirect
github.com/go-openapi/swag/fileutils v0.25.4 // indirect
github.com/go-openapi/swag/jsonname v0.25.4 // indirect
github.com/go-openapi/swag/jsonutils v0.25.4 // indirect
github.com/go-openapi/swag/loading v0.25.4 // indirect
github.com/go-openapi/swag/mangling v0.25.4 // indirect
github.com/go-openapi/swag/netutils v0.25.4 // indirect
github.com/go-openapi/swag/stringutils v0.25.4 // indirect
github.com/go-openapi/swag/typeutils v0.25.4 // indirect
github.com/go-openapi/swag/yamlutils v0.25.4 // indirect
github.com/go-test/deep v1.1.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gnostic-models v0.7.1 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grafana/grafana-app-sdk/logging v0.48.7 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.9.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
github.com/onsi/ginkgo/v2 v2.22.2 // indirect
github.com/onsi/gomega v1.36.2 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.23.2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.4 // indirect
github.com/prometheus/procfs v0.19.2 // indirect
github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/woodsbury/decimal128 v1.4.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel v1.39.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect
go.opentelemetry.io/otel/metric v1.39.0 // indirect
go.opentelemetry.io/otel/sdk v1.39.0 // indirect
go.opentelemetry.io/otel/trace v1.39.0 // indirect
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/oauth2 v0.34.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/term v0.38.0 // indirect
golang.org/x/text v0.32.0 // indirect
golang.org/x/time v0.14.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect
google.golang.org/grpc v1.77.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.34.3 // indirect
k8s.io/apiextensions-apiserver v0.34.3 // indirect
k8s.io/client-go v0.34.3 // indirect
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
)

View File

@@ -1,264 +0,0 @@
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I=
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ=
github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4=
github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80=
github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8=
github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4=
github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU=
github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ=
github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4=
github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4=
github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU=
github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y=
github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk=
github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI=
github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag=
github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA=
github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM=
github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s=
github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE=
github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48=
github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg=
github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0=
github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg=
github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8=
github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0=
github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw=
github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE=
github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw=
github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc=
github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4=
github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg=
github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls=
github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c=
github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo=
github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k=
github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw=
github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8=
github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY=
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw=
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c=
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc=
github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI=
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9pIIU=
github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc=
github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU=
google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo=
gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4=
k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk=
k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g=
k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0=
k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE=
k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A=
k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ=
k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/structured-merge-diff/v6 v6.3.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E=
sigs.k8s.io/structured-merge-diff/v6 v6.3.1/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=

View File

@@ -1,43 +0,0 @@
package investigations
// Collectable represents an item collected during investigation
#Collectable: {
id: string
createdAt: string
title: string
origin: string
type: string
queries: [...string] // +listType=atomic
timeRange: #TimeRange
datasource: #DatasourceRef
url: string
logoPath?: string
note: string
noteUpdatedAt: string
fieldConfig: string
}
#CollectableSummary: {
id: string
title: string
logoPath: string
origin: string
}
// TimeRange represents a time range with both absolute and relative values
#TimeRange: {
from: string
to: string
raw: {
from: string
to: string
}
}
// DatasourceRef is a reference to a datasource
#DatasourceRef: {
uid: string
}

View File

@@ -1,4 +0,0 @@
module: "github.com/grafana/grafana/apps/investigations"
language: {
version: "v0.11.0"
}

View File

@@ -1,43 +0,0 @@
package investigations
investigationV0alpha1: {
kind: "Investigation"
pluralName: "Investigations"
schema: {
spec: {
title: string
createdByProfile: #Person
hasCustomName: bool
isFavorite: bool
overviewNote: string
overviewNoteUpdatedAt: string
collectables: [...#Collectable] // +listType=atomic
viewMode: #ViewMode
}
}
}
// Type definition for investigation summaries
#InvestigationSummary: {
title: string
createdByProfile: #Person
hasCustomName: bool
isFavorite: bool
overviewNote: string
overviewNoteUpdatedAt: string
viewMode: #ViewMode
collectableSummaries: [...#CollectableSummary] // +listType=atomic
}
// Person represents a user profile with basic information
#Person: {
uid: string // Unique identifier for the user
name: string // Display name of the user
gravatarUrl: string // URL to user's Gravatar image
}
#ViewMode: {
mode: "compact" | "full"
showComments: bool
showTooltips: bool
}

View File

@@ -1,18 +0,0 @@
package investigations
investigationIndexV0alpha1:{
kind: "InvestigationIndex"
pluralName: "InvestigationIndexes"
schema: {
spec: {
// Title of the index, e.g. 'Favorites' or 'My Investigations'
title: string
// The Person who owns this investigation index
owner: #Person
// Array of investigation summaries
investigationSummaries: [...#InvestigationSummary] // +listType=atomic
}
}
}

View File

@@ -1,18 +0,0 @@
package investigations
manifest: {
appName: "investigations"
groupOverride: "investigations.grafana.app"
versions: {
"v0alpha1": {
codegen: {
ts: {enabled: false}
go: {enabled: true}
}
kinds: [
investigationV0alpha1,
investigationIndexV0alpha1,
]
}
}
}

View File

@@ -1,18 +0,0 @@
package v0alpha1
import "k8s.io/apimachinery/pkg/runtime/schema"
const (
// APIGroup is the API group used by all kinds in this package
APIGroup = "investigations.grafana.app"
// APIVersion is the API version used by all kinds in this package
APIVersion = "v0alpha1"
)
var (
// GroupVersion is a schema.GroupVersion consisting of the Group and Version constants for this package
GroupVersion = schema.GroupVersion{
Group: APIGroup,
Version: APIVersion,
}
)

View File

@@ -1,80 +0,0 @@
package v0alpha1
import (
"context"
"github.com/grafana/grafana-app-sdk/resource"
)
type InvestigationClient struct {
client *resource.TypedClient[*Investigation, *InvestigationList]
}
func NewInvestigationClient(client resource.Client) *InvestigationClient {
return &InvestigationClient{
client: resource.NewTypedClient[*Investigation, *InvestigationList](client, InvestigationKind()),
}
}
func NewInvestigationClientFromGenerator(generator resource.ClientGenerator) (*InvestigationClient, error) {
c, err := generator.ClientFor(InvestigationKind())
if err != nil {
return nil, err
}
return NewInvestigationClient(c), nil
}
func (c *InvestigationClient) Get(ctx context.Context, identifier resource.Identifier) (*Investigation, error) {
return c.client.Get(ctx, identifier)
}
func (c *InvestigationClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*InvestigationList, error) {
return c.client.List(ctx, namespace, opts)
}
func (c *InvestigationClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*InvestigationList, error) {
resp, err := c.client.List(ctx, namespace, resource.ListOptions{
ResourceVersion: opts.ResourceVersion,
Limit: opts.Limit,
LabelFilters: opts.LabelFilters,
FieldSelectors: opts.FieldSelectors,
})
if err != nil {
return nil, err
}
for resp.GetContinue() != "" {
page, err := c.client.List(ctx, namespace, resource.ListOptions{
Continue: resp.GetContinue(),
ResourceVersion: opts.ResourceVersion,
Limit: opts.Limit,
LabelFilters: opts.LabelFilters,
FieldSelectors: opts.FieldSelectors,
})
if err != nil {
return nil, err
}
resp.SetContinue(page.GetContinue())
resp.SetResourceVersion(page.GetResourceVersion())
resp.SetItems(append(resp.GetItems(), page.GetItems()...))
}
return resp, nil
}
func (c *InvestigationClient) Create(ctx context.Context, obj *Investigation, opts resource.CreateOptions) (*Investigation, error) {
// Make sure apiVersion and kind are set
obj.APIVersion = GroupVersion.Identifier()
obj.Kind = InvestigationKind().Kind()
return c.client.Create(ctx, obj, opts)
}
func (c *InvestigationClient) Update(ctx context.Context, obj *Investigation, opts resource.UpdateOptions) (*Investigation, error) {
return c.client.Update(ctx, obj, opts)
}
func (c *InvestigationClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*Investigation, error) {
return c.client.Patch(ctx, identifier, req, opts)
}
func (c *InvestigationClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
return c.client.Delete(ctx, identifier, opts)
}

View File

@@ -1,28 +0,0 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v0alpha1
import (
"encoding/json"
"io"
"github.com/grafana/grafana-app-sdk/resource"
)
// InvestigationJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding
type InvestigationJSONCodec struct{}
// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into`
func (*InvestigationJSONCodec) Read(reader io.Reader, into resource.Object) error {
return json.NewDecoder(reader).Decode(into)
}
// Write writes JSON-encoded bytes into `writer` marshaled from `from`
func (*InvestigationJSONCodec) Write(writer io.Writer, from resource.Object) error {
return json.NewEncoder(writer).Encode(from)
}
// Interface compliance checks
var _ resource.Codec = &InvestigationJSONCodec{}

View File

@@ -1,31 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
import (
time "time"
)
// metadata contains embedded CommonMetadata and can be extended with custom string fields
// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here
// without external reference as using the CommonMetadata reference breaks thema codegen.
type InvestigationMetadata struct {
UpdateTimestamp time.Time `json:"updateTimestamp"`
CreatedBy string `json:"createdBy"`
Uid string `json:"uid"`
CreationTimestamp time.Time `json:"creationTimestamp"`
DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"`
Finalizers []string `json:"finalizers"`
ResourceVersion string `json:"resourceVersion"`
Generation int64 `json:"generation"`
UpdatedBy string `json:"updatedBy"`
Labels map[string]string `json:"labels"`
}
// NewInvestigationMetadata creates a new InvestigationMetadata object.
func NewInvestigationMetadata() *InvestigationMetadata {
return &InvestigationMetadata{
Finalizers: []string{},
Labels: map[string]string{},
}
}

View File

@@ -1,293 +0,0 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v0alpha1
import (
"fmt"
"github.com/grafana/grafana-app-sdk/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"time"
)
// +k8s:openapi-gen=true
type Investigation struct {
metav1.TypeMeta `json:",inline" yaml:",inline"`
metav1.ObjectMeta `json:"metadata" yaml:"metadata"`
// Spec is the spec of the Investigation
Spec InvestigationSpec `json:"spec" yaml:"spec"`
}
func (o *Investigation) GetSpec() any {
return o.Spec
}
func (o *Investigation) SetSpec(spec any) error {
cast, ok := spec.(InvestigationSpec)
if !ok {
return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec)
}
o.Spec = cast
return nil
}
func (o *Investigation) GetSubresources() map[string]any {
return map[string]any{}
}
func (o *Investigation) GetSubresource(name string) (any, bool) {
switch name {
default:
return nil, false
}
}
func (o *Investigation) SetSubresource(name string, value any) error {
switch name {
default:
return fmt.Errorf("subresource '%s' does not exist", name)
}
}
func (o *Investigation) GetStaticMetadata() resource.StaticMetadata {
gvk := o.GroupVersionKind()
return resource.StaticMetadata{
Name: o.ObjectMeta.Name,
Namespace: o.ObjectMeta.Namespace,
Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind,
}
}
func (o *Investigation) SetStaticMetadata(metadata resource.StaticMetadata) {
o.Name = metadata.Name
o.Namespace = metadata.Namespace
o.SetGroupVersionKind(schema.GroupVersionKind{
Group: metadata.Group,
Version: metadata.Version,
Kind: metadata.Kind,
})
}
func (o *Investigation) GetCommonMetadata() resource.CommonMetadata {
dt := o.DeletionTimestamp
var deletionTimestamp *time.Time
if dt != nil {
deletionTimestamp = &dt.Time
}
// Legacy ExtraFields support
extraFields := make(map[string]any)
if o.Annotations != nil {
extraFields["annotations"] = o.Annotations
}
if o.ManagedFields != nil {
extraFields["managedFields"] = o.ManagedFields
}
if o.OwnerReferences != nil {
extraFields["ownerReferences"] = o.OwnerReferences
}
return resource.CommonMetadata{
UID: string(o.UID),
ResourceVersion: o.ResourceVersion,
Generation: o.Generation,
Labels: o.Labels,
CreationTimestamp: o.CreationTimestamp.Time,
DeletionTimestamp: deletionTimestamp,
Finalizers: o.Finalizers,
UpdateTimestamp: o.GetUpdateTimestamp(),
CreatedBy: o.GetCreatedBy(),
UpdatedBy: o.GetUpdatedBy(),
ExtraFields: extraFields,
}
}
func (o *Investigation) SetCommonMetadata(metadata resource.CommonMetadata) {
o.UID = types.UID(metadata.UID)
o.ResourceVersion = metadata.ResourceVersion
o.Generation = metadata.Generation
o.Labels = metadata.Labels
o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp)
if metadata.DeletionTimestamp != nil {
dt := metav1.NewTime(*metadata.DeletionTimestamp)
o.DeletionTimestamp = &dt
} else {
o.DeletionTimestamp = nil
}
o.Finalizers = metadata.Finalizers
if o.Annotations == nil {
o.Annotations = make(map[string]string)
}
if !metadata.UpdateTimestamp.IsZero() {
o.SetUpdateTimestamp(metadata.UpdateTimestamp)
}
if metadata.CreatedBy != "" {
o.SetCreatedBy(metadata.CreatedBy)
}
if metadata.UpdatedBy != "" {
o.SetUpdatedBy(metadata.UpdatedBy)
}
// Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields
if metadata.ExtraFields != nil {
if annotations, ok := metadata.ExtraFields["annotations"]; ok {
if cast, ok := annotations.(map[string]string); ok {
o.Annotations = cast
}
}
if managedFields, ok := metadata.ExtraFields["managedFields"]; ok {
if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok {
o.ManagedFields = cast
}
}
if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok {
if cast, ok := ownerReferences.([]metav1.OwnerReference); ok {
o.OwnerReferences = cast
}
}
}
}
func (o *Investigation) GetCreatedBy() string {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
return o.ObjectMeta.Annotations["grafana.com/createdBy"]
}
func (o *Investigation) SetCreatedBy(createdBy string) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy
}
func (o *Investigation) GetUpdateTimestamp() time.Time {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"])
return parsed
}
func (o *Investigation) SetUpdateTimestamp(updateTimestamp time.Time) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339)
}
func (o *Investigation) GetUpdatedBy() string {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
return o.ObjectMeta.Annotations["grafana.com/updatedBy"]
}
func (o *Investigation) SetUpdatedBy(updatedBy string) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy
}
func (o *Investigation) Copy() resource.Object {
return resource.CopyObject(o)
}
func (o *Investigation) DeepCopyObject() runtime.Object {
return o.Copy()
}
func (o *Investigation) DeepCopy() *Investigation {
cpy := &Investigation{}
o.DeepCopyInto(cpy)
return cpy
}
func (o *Investigation) DeepCopyInto(dst *Investigation) {
dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion
dst.TypeMeta.Kind = o.TypeMeta.Kind
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
o.Spec.DeepCopyInto(&dst.Spec)
}
// Interface compliance compile-time check
var _ resource.Object = &Investigation{}
// +k8s:openapi-gen=true
type InvestigationList struct {
metav1.TypeMeta `json:",inline" yaml:",inline"`
metav1.ListMeta `json:"metadata" yaml:"metadata"`
Items []Investigation `json:"items" yaml:"items"`
}
func (o *InvestigationList) DeepCopyObject() runtime.Object {
return o.Copy()
}
func (o *InvestigationList) Copy() resource.ListObject {
cpy := &InvestigationList{
TypeMeta: o.TypeMeta,
Items: make([]Investigation, len(o.Items)),
}
o.ListMeta.DeepCopyInto(&cpy.ListMeta)
for i := 0; i < len(o.Items); i++ {
if item, ok := o.Items[i].Copy().(*Investigation); ok {
cpy.Items[i] = *item
}
}
return cpy
}
func (o *InvestigationList) GetItems() []resource.Object {
items := make([]resource.Object, len(o.Items))
for i := 0; i < len(o.Items); i++ {
items[i] = &o.Items[i]
}
return items
}
func (o *InvestigationList) SetItems(items []resource.Object) {
o.Items = make([]Investigation, len(items))
for i := 0; i < len(items); i++ {
o.Items[i] = *items[i].(*Investigation)
}
}
func (o *InvestigationList) DeepCopy() *InvestigationList {
cpy := &InvestigationList{}
o.DeepCopyInto(cpy)
return cpy
}
func (o *InvestigationList) DeepCopyInto(dst *InvestigationList) {
resource.CopyObjectInto(dst, o)
}
// Interface compliance compile-time check
var _ resource.ListObject = &InvestigationList{}
// Copy methods for all subresource types
// DeepCopy creates a full deep copy of Spec
func (s *InvestigationSpec) DeepCopy() *InvestigationSpec {
cpy := &InvestigationSpec{}
s.DeepCopyInto(cpy)
return cpy
}
// DeepCopyInto deep copies Spec into another Spec object
func (s *InvestigationSpec) DeepCopyInto(dst *InvestigationSpec) {
resource.CopyObjectInto(dst, s)
}

View File

@@ -1,34 +0,0 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v0alpha1
import (
"github.com/grafana/grafana-app-sdk/resource"
)
// schema is unexported to prevent accidental overwrites
var (
schemaInvestigation = resource.NewSimpleSchema("investigations.grafana.app", "v0alpha1", &Investigation{}, &InvestigationList{}, resource.WithKind("Investigation"),
resource.WithPlural("investigations"), resource.WithScope(resource.NamespacedScope))
kindInvestigation = resource.Kind{
Schema: schemaInvestigation,
Codecs: map[resource.KindEncoding]resource.Codec{
resource.KindEncodingJSON: &InvestigationJSONCodec{},
},
}
)
// Kind returns a resource.Kind for this Schema with a JSON codec
func InvestigationKind() resource.Kind {
return kindInvestigation
}
// Schema returns a resource.SimpleSchema representation of Investigation
func InvestigationSchema() *resource.SimpleSchema {
return schemaInvestigation
}
// Interface compliance checks
var _ resource.Schema = kindInvestigation

View File

@@ -1,126 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
// Person represents a user profile with basic information
// +k8s:openapi-gen=true
type InvestigationPerson struct {
// Unique identifier for the user
Uid string `json:"uid"`
// Display name of the user
Name string `json:"name"`
// URL to user's Gravatar image
GravatarUrl string `json:"gravatarUrl"`
}
// NewInvestigationPerson creates a new InvestigationPerson object.
func NewInvestigationPerson() *InvestigationPerson {
return &InvestigationPerson{}
}
// Collectable represents an item collected during investigation
// +k8s:openapi-gen=true
type InvestigationCollectable struct {
Id string `json:"id"`
CreatedAt string `json:"createdAt"`
Title string `json:"title"`
Origin string `json:"origin"`
Type string `json:"type"`
// +listType=atomic
Queries []string `json:"queries"`
TimeRange InvestigationTimeRange `json:"timeRange"`
Datasource InvestigationDatasourceRef `json:"datasource"`
Url string `json:"url"`
LogoPath *string `json:"logoPath,omitempty"`
Note string `json:"note"`
NoteUpdatedAt string `json:"noteUpdatedAt"`
FieldConfig string `json:"fieldConfig"`
}
// NewInvestigationCollectable creates a new InvestigationCollectable object.
func NewInvestigationCollectable() *InvestigationCollectable {
return &InvestigationCollectable{
Queries: []string{},
TimeRange: *NewInvestigationTimeRange(),
Datasource: *NewInvestigationDatasourceRef(),
}
}
// TimeRange represents a time range with both absolute and relative values
// +k8s:openapi-gen=true
type InvestigationTimeRange struct {
From string `json:"from"`
To string `json:"to"`
Raw InvestigationV0alpha1TimeRangeRaw `json:"raw"`
}
// NewInvestigationTimeRange creates a new InvestigationTimeRange object.
func NewInvestigationTimeRange() *InvestigationTimeRange {
return &InvestigationTimeRange{
Raw: *NewInvestigationV0alpha1TimeRangeRaw(),
}
}
// DatasourceRef is a reference to a datasource
// +k8s:openapi-gen=true
type InvestigationDatasourceRef struct {
Uid string `json:"uid"`
}
// NewInvestigationDatasourceRef creates a new InvestigationDatasourceRef object.
func NewInvestigationDatasourceRef() *InvestigationDatasourceRef {
return &InvestigationDatasourceRef{}
}
// +k8s:openapi-gen=true
type InvestigationViewMode struct {
Mode InvestigationViewModeMode `json:"mode"`
ShowComments bool `json:"showComments"`
ShowTooltips bool `json:"showTooltips"`
}
// NewInvestigationViewMode creates a new InvestigationViewMode object.
func NewInvestigationViewMode() *InvestigationViewMode {
return &InvestigationViewMode{}
}
// +k8s:openapi-gen=true
type InvestigationSpec struct {
Title string `json:"title"`
CreatedByProfile InvestigationPerson `json:"createdByProfile"`
HasCustomName bool `json:"hasCustomName"`
IsFavorite bool `json:"isFavorite"`
OverviewNote string `json:"overviewNote"`
OverviewNoteUpdatedAt string `json:"overviewNoteUpdatedAt"`
// +listType=atomic
Collectables []InvestigationCollectable `json:"collectables"`
ViewMode InvestigationViewMode `json:"viewMode"`
}
// NewInvestigationSpec creates a new InvestigationSpec object.
func NewInvestigationSpec() *InvestigationSpec {
return &InvestigationSpec{
CreatedByProfile: *NewInvestigationPerson(),
Collectables: []InvestigationCollectable{},
ViewMode: *NewInvestigationViewMode(),
}
}
// +k8s:openapi-gen=true
type InvestigationV0alpha1TimeRangeRaw struct {
From string `json:"from"`
To string `json:"to"`
}
// NewInvestigationV0alpha1TimeRangeRaw creates a new InvestigationV0alpha1TimeRangeRaw object.
func NewInvestigationV0alpha1TimeRangeRaw() *InvestigationV0alpha1TimeRangeRaw {
return &InvestigationV0alpha1TimeRangeRaw{}
}
// +k8s:openapi-gen=true
type InvestigationViewModeMode string
const (
InvestigationViewModeModeCompact InvestigationViewModeMode = "compact"
InvestigationViewModeModeFull InvestigationViewModeMode = "full"
)

View File

@@ -1,80 +0,0 @@
package v0alpha1
import (
"context"
"github.com/grafana/grafana-app-sdk/resource"
)
type InvestigationIndexClient struct {
client *resource.TypedClient[*InvestigationIndex, *InvestigationIndexList]
}
func NewInvestigationIndexClient(client resource.Client) *InvestigationIndexClient {
return &InvestigationIndexClient{
client: resource.NewTypedClient[*InvestigationIndex, *InvestigationIndexList](client, InvestigationIndexKind()),
}
}
func NewInvestigationIndexClientFromGenerator(generator resource.ClientGenerator) (*InvestigationIndexClient, error) {
c, err := generator.ClientFor(InvestigationIndexKind())
if err != nil {
return nil, err
}
return NewInvestigationIndexClient(c), nil
}
func (c *InvestigationIndexClient) Get(ctx context.Context, identifier resource.Identifier) (*InvestigationIndex, error) {
return c.client.Get(ctx, identifier)
}
func (c *InvestigationIndexClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*InvestigationIndexList, error) {
return c.client.List(ctx, namespace, opts)
}
func (c *InvestigationIndexClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*InvestigationIndexList, error) {
resp, err := c.client.List(ctx, namespace, resource.ListOptions{
ResourceVersion: opts.ResourceVersion,
Limit: opts.Limit,
LabelFilters: opts.LabelFilters,
FieldSelectors: opts.FieldSelectors,
})
if err != nil {
return nil, err
}
for resp.GetContinue() != "" {
page, err := c.client.List(ctx, namespace, resource.ListOptions{
Continue: resp.GetContinue(),
ResourceVersion: opts.ResourceVersion,
Limit: opts.Limit,
LabelFilters: opts.LabelFilters,
FieldSelectors: opts.FieldSelectors,
})
if err != nil {
return nil, err
}
resp.SetContinue(page.GetContinue())
resp.SetResourceVersion(page.GetResourceVersion())
resp.SetItems(append(resp.GetItems(), page.GetItems()...))
}
return resp, nil
}
func (c *InvestigationIndexClient) Create(ctx context.Context, obj *InvestigationIndex, opts resource.CreateOptions) (*InvestigationIndex, error) {
// Make sure apiVersion and kind are set
obj.APIVersion = GroupVersion.Identifier()
obj.Kind = InvestigationIndexKind().Kind()
return c.client.Create(ctx, obj, opts)
}
func (c *InvestigationIndexClient) Update(ctx context.Context, obj *InvestigationIndex, opts resource.UpdateOptions) (*InvestigationIndex, error) {
return c.client.Update(ctx, obj, opts)
}
func (c *InvestigationIndexClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*InvestigationIndex, error) {
return c.client.Patch(ctx, identifier, req, opts)
}
func (c *InvestigationIndexClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
return c.client.Delete(ctx, identifier, opts)
}

View File

@@ -1,28 +0,0 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v0alpha1
import (
"encoding/json"
"io"
"github.com/grafana/grafana-app-sdk/resource"
)
// InvestigationIndexJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding
type InvestigationIndexJSONCodec struct{}
// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into`
func (*InvestigationIndexJSONCodec) Read(reader io.Reader, into resource.Object) error {
return json.NewDecoder(reader).Decode(into)
}
// Write writes JSON-encoded bytes into `writer` marshaled from `from`
func (*InvestigationIndexJSONCodec) Write(writer io.Writer, from resource.Object) error {
return json.NewEncoder(writer).Encode(from)
}
// Interface compliance checks
var _ resource.Codec = &InvestigationIndexJSONCodec{}

View File

@@ -1,31 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
import (
time "time"
)
// metadata contains embedded CommonMetadata and can be extended with custom string fields
// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here
// without external reference as using the CommonMetadata reference breaks thema codegen.
type InvestigationIndexMetadata struct {
UpdateTimestamp time.Time `json:"updateTimestamp"`
CreatedBy string `json:"createdBy"`
Uid string `json:"uid"`
CreationTimestamp time.Time `json:"creationTimestamp"`
DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"`
Finalizers []string `json:"finalizers"`
ResourceVersion string `json:"resourceVersion"`
Generation int64 `json:"generation"`
UpdatedBy string `json:"updatedBy"`
Labels map[string]string `json:"labels"`
}
// NewInvestigationIndexMetadata creates a new InvestigationIndexMetadata object.
func NewInvestigationIndexMetadata() *InvestigationIndexMetadata {
return &InvestigationIndexMetadata{
Finalizers: []string{},
Labels: map[string]string{},
}
}

View File

@@ -1,293 +0,0 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v0alpha1
import (
"fmt"
"github.com/grafana/grafana-app-sdk/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"time"
)
// +k8s:openapi-gen=true
type InvestigationIndex struct {
metav1.TypeMeta `json:",inline" yaml:",inline"`
metav1.ObjectMeta `json:"metadata" yaml:"metadata"`
// Spec is the spec of the InvestigationIndex
Spec InvestigationIndexSpec `json:"spec" yaml:"spec"`
}
func (o *InvestigationIndex) GetSpec() any {
return o.Spec
}
func (o *InvestigationIndex) SetSpec(spec any) error {
cast, ok := spec.(InvestigationIndexSpec)
if !ok {
return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec)
}
o.Spec = cast
return nil
}
func (o *InvestigationIndex) GetSubresources() map[string]any {
return map[string]any{}
}
func (o *InvestigationIndex) GetSubresource(name string) (any, bool) {
switch name {
default:
return nil, false
}
}
func (o *InvestigationIndex) SetSubresource(name string, value any) error {
switch name {
default:
return fmt.Errorf("subresource '%s' does not exist", name)
}
}
func (o *InvestigationIndex) GetStaticMetadata() resource.StaticMetadata {
gvk := o.GroupVersionKind()
return resource.StaticMetadata{
Name: o.ObjectMeta.Name,
Namespace: o.ObjectMeta.Namespace,
Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind,
}
}
func (o *InvestigationIndex) SetStaticMetadata(metadata resource.StaticMetadata) {
o.Name = metadata.Name
o.Namespace = metadata.Namespace
o.SetGroupVersionKind(schema.GroupVersionKind{
Group: metadata.Group,
Version: metadata.Version,
Kind: metadata.Kind,
})
}
func (o *InvestigationIndex) GetCommonMetadata() resource.CommonMetadata {
dt := o.DeletionTimestamp
var deletionTimestamp *time.Time
if dt != nil {
deletionTimestamp = &dt.Time
}
// Legacy ExtraFields support
extraFields := make(map[string]any)
if o.Annotations != nil {
extraFields["annotations"] = o.Annotations
}
if o.ManagedFields != nil {
extraFields["managedFields"] = o.ManagedFields
}
if o.OwnerReferences != nil {
extraFields["ownerReferences"] = o.OwnerReferences
}
return resource.CommonMetadata{
UID: string(o.UID),
ResourceVersion: o.ResourceVersion,
Generation: o.Generation,
Labels: o.Labels,
CreationTimestamp: o.CreationTimestamp.Time,
DeletionTimestamp: deletionTimestamp,
Finalizers: o.Finalizers,
UpdateTimestamp: o.GetUpdateTimestamp(),
CreatedBy: o.GetCreatedBy(),
UpdatedBy: o.GetUpdatedBy(),
ExtraFields: extraFields,
}
}
func (o *InvestigationIndex) SetCommonMetadata(metadata resource.CommonMetadata) {
o.UID = types.UID(metadata.UID)
o.ResourceVersion = metadata.ResourceVersion
o.Generation = metadata.Generation
o.Labels = metadata.Labels
o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp)
if metadata.DeletionTimestamp != nil {
dt := metav1.NewTime(*metadata.DeletionTimestamp)
o.DeletionTimestamp = &dt
} else {
o.DeletionTimestamp = nil
}
o.Finalizers = metadata.Finalizers
if o.Annotations == nil {
o.Annotations = make(map[string]string)
}
if !metadata.UpdateTimestamp.IsZero() {
o.SetUpdateTimestamp(metadata.UpdateTimestamp)
}
if metadata.CreatedBy != "" {
o.SetCreatedBy(metadata.CreatedBy)
}
if metadata.UpdatedBy != "" {
o.SetUpdatedBy(metadata.UpdatedBy)
}
// Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields
if metadata.ExtraFields != nil {
if annotations, ok := metadata.ExtraFields["annotations"]; ok {
if cast, ok := annotations.(map[string]string); ok {
o.Annotations = cast
}
}
if managedFields, ok := metadata.ExtraFields["managedFields"]; ok {
if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok {
o.ManagedFields = cast
}
}
if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok {
if cast, ok := ownerReferences.([]metav1.OwnerReference); ok {
o.OwnerReferences = cast
}
}
}
}
func (o *InvestigationIndex) GetCreatedBy() string {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
return o.ObjectMeta.Annotations["grafana.com/createdBy"]
}
func (o *InvestigationIndex) SetCreatedBy(createdBy string) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy
}
func (o *InvestigationIndex) GetUpdateTimestamp() time.Time {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"])
return parsed
}
func (o *InvestigationIndex) SetUpdateTimestamp(updateTimestamp time.Time) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339)
}
func (o *InvestigationIndex) GetUpdatedBy() string {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
return o.ObjectMeta.Annotations["grafana.com/updatedBy"]
}
func (o *InvestigationIndex) SetUpdatedBy(updatedBy string) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy
}
func (o *InvestigationIndex) Copy() resource.Object {
return resource.CopyObject(o)
}
func (o *InvestigationIndex) DeepCopyObject() runtime.Object {
return o.Copy()
}
func (o *InvestigationIndex) DeepCopy() *InvestigationIndex {
cpy := &InvestigationIndex{}
o.DeepCopyInto(cpy)
return cpy
}
func (o *InvestigationIndex) DeepCopyInto(dst *InvestigationIndex) {
dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion
dst.TypeMeta.Kind = o.TypeMeta.Kind
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
o.Spec.DeepCopyInto(&dst.Spec)
}
// Interface compliance compile-time check
var _ resource.Object = &InvestigationIndex{}
// +k8s:openapi-gen=true
type InvestigationIndexList struct {
metav1.TypeMeta `json:",inline" yaml:",inline"`
metav1.ListMeta `json:"metadata" yaml:"metadata"`
Items []InvestigationIndex `json:"items" yaml:"items"`
}
func (o *InvestigationIndexList) DeepCopyObject() runtime.Object {
return o.Copy()
}
func (o *InvestigationIndexList) Copy() resource.ListObject {
cpy := &InvestigationIndexList{
TypeMeta: o.TypeMeta,
Items: make([]InvestigationIndex, len(o.Items)),
}
o.ListMeta.DeepCopyInto(&cpy.ListMeta)
for i := 0; i < len(o.Items); i++ {
if item, ok := o.Items[i].Copy().(*InvestigationIndex); ok {
cpy.Items[i] = *item
}
}
return cpy
}
func (o *InvestigationIndexList) GetItems() []resource.Object {
items := make([]resource.Object, len(o.Items))
for i := 0; i < len(o.Items); i++ {
items[i] = &o.Items[i]
}
return items
}
func (o *InvestigationIndexList) SetItems(items []resource.Object) {
o.Items = make([]InvestigationIndex, len(items))
for i := 0; i < len(items); i++ {
o.Items[i] = *items[i].(*InvestigationIndex)
}
}
func (o *InvestigationIndexList) DeepCopy() *InvestigationIndexList {
cpy := &InvestigationIndexList{}
o.DeepCopyInto(cpy)
return cpy
}
func (o *InvestigationIndexList) DeepCopyInto(dst *InvestigationIndexList) {
resource.CopyObjectInto(dst, o)
}
// Interface compliance compile-time check
var _ resource.ListObject = &InvestigationIndexList{}
// Copy methods for all subresource types
// DeepCopy creates a full deep copy of Spec
func (s *InvestigationIndexSpec) DeepCopy() *InvestigationIndexSpec {
cpy := &InvestigationIndexSpec{}
s.DeepCopyInto(cpy)
return cpy
}
// DeepCopyInto deep copies Spec into another Spec object
func (s *InvestigationIndexSpec) DeepCopyInto(dst *InvestigationIndexSpec) {
resource.CopyObjectInto(dst, s)
}

View File

@@ -1,34 +0,0 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v0alpha1
import (
"github.com/grafana/grafana-app-sdk/resource"
)
// schema is unexported to prevent accidental overwrites
var (
schemaInvestigationIndex = resource.NewSimpleSchema("investigations.grafana.app", "v0alpha1", &InvestigationIndex{}, &InvestigationIndexList{}, resource.WithKind("InvestigationIndex"),
resource.WithPlural("investigationindexes"), resource.WithScope(resource.NamespacedScope))
kindInvestigationIndex = resource.Kind{
Schema: schemaInvestigationIndex,
Codecs: map[resource.KindEncoding]resource.Codec{
resource.KindEncodingJSON: &InvestigationIndexJSONCodec{},
},
}
)
// Kind returns a resource.Kind for this Schema with a JSON codec
func InvestigationIndexKind() resource.Kind {
return kindInvestigationIndex
}
// Schema returns a resource.SimpleSchema representation of InvestigationIndex
func InvestigationIndexSchema() *resource.SimpleSchema {
return schemaInvestigationIndex
}
// Interface compliance checks
var _ resource.Schema = kindInvestigationIndex

View File

@@ -1,94 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
// Person represents a user profile with basic information
// +k8s:openapi-gen=true
type InvestigationIndexPerson struct {
// Unique identifier for the user
Uid string `json:"uid"`
// Display name of the user
Name string `json:"name"`
// URL to user's Gravatar image
GravatarUrl string `json:"gravatarUrl"`
}
// NewInvestigationIndexPerson creates a new InvestigationIndexPerson object.
func NewInvestigationIndexPerson() *InvestigationIndexPerson {
return &InvestigationIndexPerson{}
}
// Type definition for investigation summaries
// +k8s:openapi-gen=true
type InvestigationIndexInvestigationSummary struct {
Title string `json:"title"`
CreatedByProfile InvestigationIndexPerson `json:"createdByProfile"`
HasCustomName bool `json:"hasCustomName"`
IsFavorite bool `json:"isFavorite"`
OverviewNote string `json:"overviewNote"`
OverviewNoteUpdatedAt string `json:"overviewNoteUpdatedAt"`
ViewMode InvestigationIndexViewMode `json:"viewMode"`
// +listType=atomic
CollectableSummaries []InvestigationIndexCollectableSummary `json:"collectableSummaries"`
}
// NewInvestigationIndexInvestigationSummary creates a new InvestigationIndexInvestigationSummary object.
func NewInvestigationIndexInvestigationSummary() *InvestigationIndexInvestigationSummary {
return &InvestigationIndexInvestigationSummary{
CreatedByProfile: *NewInvestigationIndexPerson(),
ViewMode: *NewInvestigationIndexViewMode(),
CollectableSummaries: []InvestigationIndexCollectableSummary{},
}
}
// +k8s:openapi-gen=true
type InvestigationIndexViewMode struct {
Mode InvestigationIndexViewModeMode `json:"mode"`
ShowComments bool `json:"showComments"`
ShowTooltips bool `json:"showTooltips"`
}
// NewInvestigationIndexViewMode creates a new InvestigationIndexViewMode object.
func NewInvestigationIndexViewMode() *InvestigationIndexViewMode {
return &InvestigationIndexViewMode{}
}
// +k8s:openapi-gen=true
type InvestigationIndexCollectableSummary struct {
Id string `json:"id"`
Title string `json:"title"`
LogoPath string `json:"logoPath"`
Origin string `json:"origin"`
}
// NewInvestigationIndexCollectableSummary creates a new InvestigationIndexCollectableSummary object.
func NewInvestigationIndexCollectableSummary() *InvestigationIndexCollectableSummary {
return &InvestigationIndexCollectableSummary{}
}
// +k8s:openapi-gen=true
type InvestigationIndexSpec struct {
// Title of the index, e.g. 'Favorites' or 'My Investigations'
Title string `json:"title"`
// The Person who owns this investigation index
Owner InvestigationIndexPerson `json:"owner"`
// Array of investigation summaries
// +listType=atomic
InvestigationSummaries []InvestigationIndexInvestigationSummary `json:"investigationSummaries"`
}
// NewInvestigationIndexSpec creates a new InvestigationIndexSpec object.
func NewInvestigationIndexSpec() *InvestigationIndexSpec {
return &InvestigationIndexSpec{
Owner: *NewInvestigationIndexPerson(),
InvestigationSummaries: []InvestigationIndexInvestigationSummary{},
}
}
// +k8s:openapi-gen=true
type InvestigationIndexViewModeMode string
const (
InvestigationIndexViewModeModeCompact InvestigationIndexViewModeMode = "compact"
InvestigationIndexViewModeModeFull InvestigationIndexViewModeMode = "full"
)

View File

@@ -1,44 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
// +k8s:openapi-gen=true
type InvestigationIndexstatusOperatorState struct {
// lastEvaluation is the ResourceVersion last evaluated
LastEvaluation string `json:"lastEvaluation"`
// state describes the state of the lastEvaluation.
// It is limited to three possible states for machine evaluation.
State InvestigationIndexStatusOperatorStateState `json:"state"`
// descriptiveState is an optional more descriptive state field which has no requirements on format
DescriptiveState *string `json:"descriptiveState,omitempty"`
// details contains any extra information that is operator-specific
Details map[string]interface{} `json:"details,omitempty"`
}
// NewInvestigationIndexstatusOperatorState creates a new InvestigationIndexstatusOperatorState object.
func NewInvestigationIndexstatusOperatorState() *InvestigationIndexstatusOperatorState {
return &InvestigationIndexstatusOperatorState{}
}
// +k8s:openapi-gen=true
type InvestigationIndexStatus struct {
// operatorStates is a map of operator ID to operator state evaluations.
// Any operator which consumes this kind SHOULD add its state evaluation information to this field.
OperatorStates map[string]InvestigationIndexstatusOperatorState `json:"operatorStates,omitempty"`
// additionalFields is reserved for future use
AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"`
}
// NewInvestigationIndexStatus creates a new InvestigationIndexStatus object.
func NewInvestigationIndexStatus() *InvestigationIndexStatus {
return &InvestigationIndexStatus{}
}
// +k8s:openapi-gen=true
type InvestigationIndexStatusOperatorStateState string
const (
InvestigationIndexStatusOperatorStateStateSuccess InvestigationIndexStatusOperatorStateState = "success"
InvestigationIndexStatusOperatorStateStateInProgress InvestigationIndexStatusOperatorStateState = "in_progress"
InvestigationIndexStatusOperatorStateStateFailed InvestigationIndexStatusOperatorStateState = "failed"
)

File diff suppressed because it is too large Load Diff

View File

@@ -1,136 +0,0 @@
//
// This file is generated by grafana-app-sdk
// DO NOT EDIT
//
package apis
import (
"encoding/json"
"fmt"
"strings"
"github.com/grafana/grafana-app-sdk/app"
"github.com/grafana/grafana-app-sdk/resource"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kube-openapi/pkg/spec3"
"k8s.io/kube-openapi/pkg/validation/spec"
v0alpha1 "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1"
)
var (
rawSchemaInvestigationv0alpha1 = []byte(`{"Collectable":{"additionalProperties":false,"description":"Collectable represents an item collected during investigation","properties":{"createdAt":{"type":"string"},"datasource":{"$ref":"#/components/schemas/DatasourceRef"},"fieldConfig":{"type":"string"},"id":{"type":"string"},"logoPath":{"type":"string"},"note":{"type":"string"},"noteUpdatedAt":{"type":"string"},"origin":{"type":"string"},"queries":{"description":"+listType=atomic","items":{"type":"string"},"type":"array"},"timeRange":{"$ref":"#/components/schemas/TimeRange"},"title":{"type":"string"},"type":{"type":"string"},"url":{"type":"string"}},"required":["id","createdAt","title","origin","type","queries","timeRange","datasource","url","note","noteUpdatedAt","fieldConfig"],"type":"object"},"DatasourceRef":{"additionalProperties":false,"description":"DatasourceRef is a reference to a datasource","properties":{"uid":{"type":"string"}},"required":["uid"],"type":"object"},"Investigation":{"properties":{"spec":{"$ref":"#/components/schemas/spec"}},"required":["spec"]},"Person":{"additionalProperties":false,"description":"Person represents a user profile with basic information","properties":{"gravatarUrl":{"description":"URL to user's Gravatar image","type":"string"},"name":{"description":"Display name of the user","type":"string"},"uid":{"description":"Unique identifier for the user","type":"string"}},"required":["uid","name","gravatarUrl"],"type":"object"},"TimeRange":{"additionalProperties":false,"description":"TimeRange represents a time range with both absolute and relative values","properties":{"from":{"type":"string"},"raw":{"additionalProperties":false,"properties":{"from":{"type":"string"},"to":{"type":"string"}},"required":["from","to"],"type":"object"},"to":{"type":"string"}},"required":["from","to","raw"],"type":"object"},"ViewMode":{"additionalProperties":false,"properties":{"mode":{"enum":["compact","full"],"type":"string"},"showComments":{"type":"boolean"},"showTooltips":{"type":"boolean"}},"required":["mode","showComments","showTooltips"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"collectables":{"description":"+listType=atomic","items":{"$ref":"#/components/schemas/Collectable"},"type":"array"},"createdByProfile":{"$ref":"#/components/schemas/Person"},"hasCustomName":{"type":"boolean"},"isFavorite":{"type":"boolean"},"overviewNote":{"type":"string"},"overviewNoteUpdatedAt":{"type":"string"},"title":{"type":"string"},"viewMode":{"$ref":"#/components/schemas/ViewMode"}},"required":["title","createdByProfile","hasCustomName","isFavorite","overviewNote","overviewNoteUpdatedAt","collectables","viewMode"],"type":"object"}}`)
versionSchemaInvestigationv0alpha1 app.VersionSchema
_ = json.Unmarshal(rawSchemaInvestigationv0alpha1, &versionSchemaInvestigationv0alpha1)
rawSchemaInvestigationIndexv0alpha1 = []byte(`{"CollectableSummary":{"additionalProperties":false,"properties":{"id":{"type":"string"},"logoPath":{"type":"string"},"origin":{"type":"string"},"title":{"type":"string"}},"required":["id","title","logoPath","origin"],"type":"object"},"InvestigationIndex":{"properties":{"spec":{"$ref":"#/components/schemas/spec"}},"required":["spec"]},"InvestigationSummary":{"additionalProperties":false,"description":"Type definition for investigation summaries","properties":{"collectableSummaries":{"description":"+listType=atomic","items":{"$ref":"#/components/schemas/CollectableSummary"},"type":"array"},"createdByProfile":{"$ref":"#/components/schemas/Person"},"hasCustomName":{"type":"boolean"},"isFavorite":{"type":"boolean"},"overviewNote":{"type":"string"},"overviewNoteUpdatedAt":{"type":"string"},"title":{"type":"string"},"viewMode":{"$ref":"#/components/schemas/ViewMode"}},"required":["title","createdByProfile","hasCustomName","isFavorite","overviewNote","overviewNoteUpdatedAt","viewMode","collectableSummaries"],"type":"object"},"Person":{"additionalProperties":false,"description":"Person represents a user profile with basic information","properties":{"gravatarUrl":{"description":"URL to user's Gravatar image","type":"string"},"name":{"description":"Display name of the user","type":"string"},"uid":{"description":"Unique identifier for the user","type":"string"}},"required":["uid","name","gravatarUrl"],"type":"object"},"ViewMode":{"additionalProperties":false,"properties":{"mode":{"enum":["compact","full"],"type":"string"},"showComments":{"type":"boolean"},"showTooltips":{"type":"boolean"}},"required":["mode","showComments","showTooltips"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"investigationSummaries":{"description":"Array of investigation summaries\n+listType=atomic","items":{"$ref":"#/components/schemas/InvestigationSummary"},"type":"array"},"owner":{"$ref":"#/components/schemas/Person","description":"The Person who owns this investigation index"},"title":{"description":"Title of the index, e.g. 'Favorites' or 'My Investigations'","type":"string"}},"required":["title","owner","investigationSummaries"],"type":"object"}}`)
versionSchemaInvestigationIndexv0alpha1 app.VersionSchema
_ = json.Unmarshal(rawSchemaInvestigationIndexv0alpha1, &versionSchemaInvestigationIndexv0alpha1)
)
var appManifestData = app.ManifestData{
AppName: "investigations",
Group: "investigations.grafana.app",
PreferredVersion: "v0alpha1",
Versions: []app.ManifestVersion{
{
Name: "v0alpha1",
Served: true,
Kinds: []app.ManifestVersionKind{
{
Kind: "Investigation",
Plural: "Investigations",
Scope: "Namespaced",
Conversion: false,
Schema: &versionSchemaInvestigationv0alpha1,
},
{
Kind: "InvestigationIndex",
Plural: "InvestigationIndexes",
Scope: "Namespaced",
Conversion: false,
Schema: &versionSchemaInvestigationIndexv0alpha1,
},
},
Routes: app.ManifestVersionRoutes{
Namespaced: map[string]spec3.PathProps{},
Cluster: map[string]spec3.PathProps{},
Schemas: map[string]spec.Schema{},
},
},
},
}
func LocalManifest() app.Manifest {
return app.NewEmbeddedManifest(appManifestData)
}
func RemoteManifest() app.Manifest {
return app.NewAPIServerManifest("investigations")
}
var kindVersionToGoType = map[string]resource.Kind{
"Investigation/v0alpha1": v0alpha1.InvestigationKind(),
"InvestigationIndex/v0alpha1": v0alpha1.InvestigationIndexKind(),
}
// ManifestGoTypeAssociator returns the associated resource.Kind instance for a given Kind and Version, if one exists.
// If there is no association for the provided Kind and Version, exists will return false.
func ManifestGoTypeAssociator(kind, version string) (goType resource.Kind, exists bool) {
goType, exists = kindVersionToGoType[fmt.Sprintf("%s/%s", kind, version)]
return goType, exists
}
var customRouteToGoResponseType = map[string]any{}
// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists.
// kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths.
// If there is no association for the provided kind, version, custom route path, and method, exists will return false.
// Resource routes (those without a kind) should prefix their route with "<namespace>/" if the route is namespaced (otherwise the route is assumed to be cluster-scope)
func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) {
if len(path) > 0 && path[0] == '/' {
path = path[1:]
}
goType, exists = customRouteToGoResponseType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
return goType, exists
}
var customRouteToGoParamsType = map[string]runtime.Object{}
func ManifestCustomRouteQueryAssociator(kind, version, path, verb string) (goType runtime.Object, exists bool) {
if len(path) > 0 && path[0] == '/' {
path = path[1:]
}
goType, exists = customRouteToGoParamsType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
return goType, exists
}
var customRouteToGoRequestBodyType = map[string]any{}
func ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb string) (goType any, exists bool) {
if len(path) > 0 && path[0] == '/' {
path = path[1:]
}
goType, exists = customRouteToGoRequestBodyType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
return goType, exists
}
type GoTypeAssociator struct{}
func NewGoTypeAssociator() *GoTypeAssociator {
return &GoTypeAssociator{}
}
func (g *GoTypeAssociator) KindToGoType(kind, version string) (goType resource.Kind, exists bool) {
return ManifestGoTypeAssociator(kind, version)
}
func (g *GoTypeAssociator) CustomRouteReturnGoType(kind, version, path, verb string) (goType any, exists bool) {
return ManifestCustomRouteResponsesAssociator(kind, version, path, verb)
}
func (g *GoTypeAssociator) CustomRouteQueryGoType(kind, version, path, verb string) (goType runtime.Object, exists bool) {
return ManifestCustomRouteQueryAssociator(kind, version, path, verb)
}
func (g *GoTypeAssociator) CustomRouteRequestBodyGoType(kind, version, path, verb string) (goType any, exists bool) {
return ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb)
}

View File

@@ -1,62 +0,0 @@
package app
import (
"context"
"github.com/grafana/grafana-app-sdk/app"
"github.com/grafana/grafana-app-sdk/operator"
"github.com/grafana/grafana-app-sdk/resource"
"github.com/grafana/grafana-app-sdk/simple"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/klog/v2"
investigationsv0alpha1 "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1"
)
func New(cfg app.Config) (app.App, error) {
var err error
simpleConfig := simple.AppConfig{
Name: "investigation",
KubeConfig: cfg.KubeConfig,
InformerConfig: simple.AppInformerConfig{
InformerOptions: operator.InformerOptions{
ErrorHandler: func(_ context.Context, err error) {
klog.ErrorS(err, "Informer processing error")
},
},
},
ManagedKinds: []simple.AppManagedKind{
{
Kind: investigationsv0alpha1.InvestigationKind(),
},
{
Kind: investigationsv0alpha1.InvestigationIndexKind(),
},
},
}
a, err := simple.NewApp(simpleConfig)
if err != nil {
return nil, err
}
err = a.ValidateManifest(cfg.ManifestData)
if err != nil {
return nil, err
}
return a, nil
}
func GetKinds() map[schema.GroupVersion][]resource.Kind {
gv := schema.GroupVersion{
Group: investigationsv0alpha1.InvestigationKind().Group(),
Version: investigationsv0alpha1.InvestigationKind().Version(),
}
return map[schema.GroupVersion][]resource.Kind{
gv: {
investigationsv0alpha1.InvestigationKind(),
investigationsv0alpha1.InvestigationIndexKind(),
},
}
}

View File

@@ -1,49 +0,0 @@
/*
* This file was generated by grafana-app-sdk. DO NOT EDIT.
*/
import { Spec } from './types.spec.gen';
import { Status } from './types.status.gen';
export interface Metadata {
name: string;
namespace: string;
generateName?: string;
selfLink?: string;
uid?: string;
resourceVersion?: string;
generation?: number;
creationTimestamp?: string;
deletionTimestamp?: string;
deletionGracePeriodSeconds?: number;
labels?: Record<string, string>;
annotations?: Record<string, string>;
ownerReferences?: OwnerReference[];
finalizers?: string[];
managedFields?: ManagedFieldsEntry[];
}
export interface OwnerReference {
apiVersion: string;
kind: string;
name: string;
uid: string;
controller?: boolean;
blockOwnerDeletion?: boolean;
}
export interface ManagedFieldsEntry {
manager?: string;
operation?: string;
apiVersion?: string;
time?: string;
fieldsType?: string;
subresource?: string;
}
export interface Investigation {
kind: string;
apiVersion: string;
metadata: Metadata;
spec: Spec;
status: Status;
}

View File

@@ -1,30 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
// metadata contains embedded CommonMetadata and can be extended with custom string fields
// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here
// without external reference as using the CommonMetadata reference breaks thema codegen.
export interface Metadata {
updateTimestamp: string;
createdBy: string;
uid: string;
creationTimestamp: string;
deletionTimestamp?: string;
finalizers: string[];
resourceVersion: string;
generation: number;
updatedBy: string;
labels: Record<string, string>;
}
export const defaultMetadata = (): Metadata => ({
updateTimestamp: "",
createdBy: "",
uid: "",
creationTimestamp: "",
finalizers: [],
resourceVersion: "",
generation: 0,
updatedBy: "",
labels: {},
});

View File

@@ -1,115 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
// Person represents a user profile with basic information
export interface Person {
// Unique identifier for the user
uid: string;
// Display name of the user
name: string;
// URL to user's Gravatar image
gravatarUrl: string;
}
export const defaultPerson = (): Person => ({
uid: "",
name: "",
gravatarUrl: "",
});
// Collectable represents an item collected during investigation
export interface Collectable {
id: string;
createdAt: string;
title: string;
origin: string;
type: string;
// +listType=atomic
queries: string[];
timeRange: TimeRange;
datasource: DatasourceRef;
url: string;
logoPath?: string;
note: string;
noteUpdatedAt: string;
fieldConfig: string;
}
export const defaultCollectable = (): Collectable => ({
id: "",
createdAt: "",
title: "",
origin: "",
type: "",
queries: [],
timeRange: defaultTimeRange(),
datasource: defaultDatasourceRef(),
url: "",
note: "",
noteUpdatedAt: "",
fieldConfig: "",
});
// TimeRange represents a time range with both absolute and relative values
export interface TimeRange {
from: string;
to: string;
raw: {
from: string;
to: string;
};
}
export const defaultTimeRange = (): TimeRange => ({
from: "",
to: "",
raw: {
from: "",
to: "",
},
});
// DatasourceRef is a reference to a datasource
export interface DatasourceRef {
uid: string;
}
export const defaultDatasourceRef = (): DatasourceRef => ({
uid: "",
});
export interface ViewMode {
mode: "compact" | "full";
showComments: boolean;
showTooltips: boolean;
}
export const defaultViewMode = (): ViewMode => ({
mode: "compact",
showComments: false,
showTooltips: false,
});
// spec is the schema of our resource
export interface Spec {
title: string;
createdByProfile: Person;
hasCustomName: boolean;
isFavorite: boolean;
overviewNote: string;
overviewNoteUpdatedAt: string;
// +listType=atomic
collectables: Collectable[];
viewMode: ViewMode;
}
export const defaultSpec = (): Spec => ({
title: "",
createdByProfile: defaultPerson(),
hasCustomName: false,
isFavorite: false,
overviewNote: "",
overviewNoteUpdatedAt: "",
collectables: [],
viewMode: defaultViewMode(),
});

View File

@@ -1,30 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
export interface OperatorState {
// lastEvaluation is the ResourceVersion last evaluated
lastEvaluation: string;
// state describes the state of the lastEvaluation.
// It is limited to three possible states for machine evaluation.
state: "success" | "in_progress" | "failed";
// descriptiveState is an optional more descriptive state field which has no requirements on format
descriptiveState?: string;
// details contains any extra information that is operator-specific
details?: Record<string, any>;
}
export const defaultOperatorState = (): OperatorState => ({
lastEvaluation: "",
state: "success",
});
export interface Status {
// operatorStates is a map of operator ID to operator state evaluations.
// Any operator which consumes this kind SHOULD add its state evaluation information to this field.
operatorStates?: Record<string, OperatorState>;
// additionalFields is reserved for future use
additionalFields?: Record<string, any>;
}
export const defaultStatus = (): Status => ({
});

View File

@@ -1,49 +0,0 @@
/*
* This file was generated by grafana-app-sdk. DO NOT EDIT.
*/
import { Spec } from './types.spec.gen';
import { Status } from './types.status.gen';
export interface Metadata {
name: string;
namespace: string;
generateName?: string;
selfLink?: string;
uid?: string;
resourceVersion?: string;
generation?: number;
creationTimestamp?: string;
deletionTimestamp?: string;
deletionGracePeriodSeconds?: number;
labels?: Record<string, string>;
annotations?: Record<string, string>;
ownerReferences?: OwnerReference[];
finalizers?: string[];
managedFields?: ManagedFieldsEntry[];
}
export interface OwnerReference {
apiVersion: string;
kind: string;
name: string;
uid: string;
controller?: boolean;
blockOwnerDeletion?: boolean;
}
export interface ManagedFieldsEntry {
manager?: string;
operation?: string;
apiVersion?: string;
time?: string;
fieldsType?: string;
subresource?: string;
}
export interface InvestigationIndex {
kind: string;
apiVersion: string;
metadata: Metadata;
spec: Spec;
status: Status;
}

View File

@@ -1,30 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
// metadata contains embedded CommonMetadata and can be extended with custom string fields
// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here
// without external reference as using the CommonMetadata reference breaks thema codegen.
export interface Metadata {
updateTimestamp: string;
createdBy: string;
uid: string;
creationTimestamp: string;
deletionTimestamp?: string;
finalizers: string[];
resourceVersion: string;
generation: number;
updatedBy: string;
labels: Record<string, string>;
}
export const defaultMetadata = (): Metadata => ({
updateTimestamp: "",
createdBy: "",
uid: "",
creationTimestamp: "",
finalizers: [],
resourceVersion: "",
generation: 0,
updatedBy: "",
labels: {},
});

View File

@@ -1,84 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
// Person represents a user profile with basic information
export interface Person {
// Unique identifier for the user
uid: string;
// Display name of the user
name: string;
// URL to user's Gravatar image
gravatarUrl: string;
}
export const defaultPerson = (): Person => ({
uid: "",
name: "",
gravatarUrl: "",
});
// Type definition for investigation summaries
export interface InvestigationSummary {
title: string;
createdByProfile: Person;
hasCustomName: boolean;
isFavorite: boolean;
overviewNote: string;
overviewNoteUpdatedAt: string;
viewMode: ViewMode;
// +listType=atomic
collectableSummaries: CollectableSummary[];
}
export const defaultInvestigationSummary = (): InvestigationSummary => ({
title: "",
createdByProfile: defaultPerson(),
hasCustomName: false,
isFavorite: false,
overviewNote: "",
overviewNoteUpdatedAt: "",
viewMode: defaultViewMode(),
collectableSummaries: [],
});
export interface ViewMode {
mode: "compact" | "full";
showComments: boolean;
showTooltips: boolean;
}
export const defaultViewMode = (): ViewMode => ({
mode: "compact",
showComments: false,
showTooltips: false,
});
export interface CollectableSummary {
id: string;
title: string;
logoPath: string;
origin: string;
}
export const defaultCollectableSummary = (): CollectableSummary => ({
id: "",
title: "",
logoPath: "",
origin: "",
});
export interface Spec {
// Title of the index, e.g. 'Favorites' or 'My Investigations'
title: string;
// The Person who owns this investigation index
owner: Person;
// Array of investigation summaries
// +listType=atomic
investigationSummaries: InvestigationSummary[];
}
export const defaultSpec = (): Spec => ({
title: "",
owner: defaultPerson(),
investigationSummaries: [],
});

View File

@@ -1,30 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
export interface OperatorState {
// lastEvaluation is the ResourceVersion last evaluated
lastEvaluation: string;
// state describes the state of the lastEvaluation.
// It is limited to three possible states for machine evaluation.
state: "success" | "in_progress" | "failed";
// descriptiveState is an optional more descriptive state field which has no requirements on format
descriptiveState?: string;
// details contains any extra information that is operator-specific
details?: Record<string, any>;
}
export const defaultOperatorState = (): OperatorState => ({
lastEvaluation: "",
state: "success",
});
export interface Status {
// operatorStates is a map of operator ID to operator state evaluations.
// Any operator which consumes this kind SHOULD add its state evaluation information to this field.
operatorStates?: Record<string, OperatorState>;
// additionalFields is reserved for future use
additionalFields?: Record<string, any>;
}
export const defaultStatus = (): Status => ({
});

2
go.mod
View File

@@ -250,7 +250,6 @@ require (
github.com/grafana/grafana/apps/example v0.0.0-20251027162426-edef69fdc82b // @grafana/grafana-app-platform-squad
github.com/grafana/grafana/apps/folder v0.0.0 // @grafana/grafana-search-and-storage
github.com/grafana/grafana/apps/iam v0.0.0 // @grafana/identity-access-team
github.com/grafana/grafana/apps/investigations v0.0.0 // @fcjack @matryer
github.com/grafana/grafana/apps/logsdrilldown v0.0.0 // @grafana/observability-logs
github.com/grafana/grafana/apps/playlist v0.0.0 // @grafana/grafana-app-platform-squad
github.com/grafana/grafana/apps/plugins v0.0.0 // @grafana/plugins-platform-backend
@@ -284,7 +283,6 @@ replace (
github.com/grafana/grafana/apps/dashboard => ./apps/dashboard
github.com/grafana/grafana/apps/folder => ./apps/folder
github.com/grafana/grafana/apps/iam => ./apps/iam
github.com/grafana/grafana/apps/investigations => ./apps/investigations
github.com/grafana/grafana/apps/logsdrilldown => ./apps/logsdrilldown
github.com/grafana/grafana/apps/playlist => ./apps/playlist
github.com/grafana/grafana/apps/plugins => ./apps/plugins

View File

@@ -17,7 +17,6 @@ use (
./apps/example
./apps/folder
./apps/iam
./apps/investigations
./apps/logsdrilldown
./apps/playlist
./apps/plugins

View File

@@ -76,7 +76,8 @@
"plugin:test:ci": "nx run-many -t test:ci --projects='tag:scope:plugin' --maxParallel=2",
"plugin:i18n-extract": "nx run-many -t i18n-extract --projects='tag:scope:plugin'",
"generate-apis": "yarn workspace @grafana/api-clients generate-apis",
"generate:api-client": "yarn workspace @grafana/api-clients generate:api-client"
"generate:api-client": "yarn workspace @grafana/api-clients generate:api-client",
"generate:openapi": "yarn workspace @grafana/openapi generate:openapi"
},
"grafana": {
"whatsNewUrl": "https://grafana.com/docs/grafana/next/whatsnew/whats-new-in-v%[1]s-%[2]s/",

View File

@@ -157,8 +157,7 @@
"typecheck": "tsc --emitDeclarationOnly false --noEmit",
"prepack": "cp package.json package.json.bak && node ../../scripts/prepare-npm-package.js",
"postpack": "mv package.json.bak package.json",
"process-specs": "NODE_OPTIONS='--disable-warning=ExperimentalWarning' node --experimental-strip-types src/scripts/process-specs.ts",
"generate-apis": "yarn process-specs && NODE_OPTIONS='--disable-warning=ExperimentalWarning' rtk-query-codegen-openapi ./src/scripts/generate-rtk-apis.ts",
"generate-apis": "yarn workspace @grafana/openapi process-specs && NODE_OPTIONS='--disable-warning=ExperimentalWarning' rtk-query-codegen-openapi ./src/scripts/generate-rtk-apis.ts",
"generate:api-client": "NODE_OPTIONS='--experimental-strip-types --disable-warning=ExperimentalWarning' plop --plopfile src/generator/plopfile.ts"
},
"devDependencies": {

View File

@@ -45,7 +45,7 @@ If an error about a missing OpenAPI schema appears, check that:
1. The API group and version exist in the backend
2. The `TestIntegrationOpenAPIs` test has been run to generate the schema (step 1 in the [main API documentation](../../public/app/api/README.md)).
3. The schema file exists at `data/openapi/<group>-<version>.json`
3. The schema file exists at `packages/grafana-openapi/src/apis/<group>-<version>.json`
### Validation Errors

View File

@@ -66,7 +66,7 @@ export const runGenerateApis =
let command;
if (isEnterprise) {
command =
'yarn workspace @grafana/api-clients process-specs && npx rtk-query-codegen-openapi ./local/generate-enterprise-apis.ts';
'yarn workspace @grafana/openapi process-specs && npx rtk-query-codegen-openapi ./local/generate-enterprise-apis.ts';
} else {
command = 'yarn workspace @grafana/api-clients generate-apis';
}

View File

@@ -30,7 +30,7 @@ const createAPIConfig = (app: string, version: string, filterEndpoints?: Endpoin
const filePath = `../clients/rtkq/${app}/${version}/endpoints.gen.ts`;
return {
[filePath]: {
schemaFile: path.join(basePath, `data/openapi/${app}.grafana.app-${version}.json`),
schemaFile: path.join(basePath, `packages/grafana-openapi/src/apis/${app}.grafana.app-${version}.json`),
apiFile: `../clients/rtkq/${app}/${version}/baseAPI.ts`,
filterEndpoints,
tag: true,

View File

@@ -787,11 +787,6 @@ export interface FeatureToggles {
*/
lokiLabelNamesQueryApi?: boolean;
/**
* Enable the investigations backend API
* @default false
*/
investigationsBackend?: boolean;
/**
* Enable folder's api server counts
* @default false
*/

View File

@@ -0,0 +1,2 @@
api/*.json linguist-generated
apis/*.json linguist-generated

View File

@@ -0,0 +1,3 @@
# Changelog
All notable changes to this project will be documented in this file.

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2015 Grafana Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,5 @@
# Grafana OpenApi Library
> **@grafana/openapi is currently in ALPHA**.
This package holds open api specs

View File

@@ -0,0 +1,60 @@
{
"author": "Grafana Labs",
"license": "Apache-2.0",
"name": "@grafana/openapi",
"version": "12.4.0-pre",
"description": "Grafana OpenApi Library",
"keywords": [
"grafana",
"openapi",
"typescript"
],
"type": "module",
"sideEffects": false,
"repository": {
"type": "git",
"url": "git+http://github.com/grafana/grafana.git",
"directory": "packages/grafana-openapi"
},
"exports": {
"./package.json": "./package.json",
"./api/*": {
"import": "./dist/api/*.json",
"require": "./dist/api/*.json"
},
"./apis/*": {
"import": "./dist/apis/*.json",
"require": "./dist/apis/*.json"
}
},
"publishConfig": {
"access": "public"
},
"files": [
"dist",
"./README.md",
"./CHANGELOG.md",
"LICENSE_APACHE2"
],
"scripts": {
"build": "yarn clean && yarn create:folders && yarn copy:dist",
"clean": "rm -rf ./dist && rm -f package.tgz",
"copy:api": "cp ../../public/openapi3.json ./src/api",
"copy:dist": "cp ./src/apis/* ./dist/apis && cp ./src/api/* ./dist/api",
"create:folders": "mkdir -p dist/api dist/apis",
"format": "prettier \"**/*.json\" --write --log-level=warn",
"generate:openapi": "make -C ../../ generate-openapi",
"typecheck": "",
"prepack": "cp package.json package.json.bak && node ../../scripts/prepare-npm-package.js",
"postpack": "mv package.json.bak package.json",
"process-specs": "node src/scripts/process-specs.ts && yarn copy:api && yarn format"
},
"engines": {
"node": ">= 24 <25"
},
"packageManager": "yarn@4.11.0",
"devDependencies": {
"openapi-types": "^12.1.3",
"prettier": "3.6.2"
}
}

View File

@@ -0,0 +1,8 @@
{
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "library",
"tags": ["scope:package"],
"targets": {
"build": {}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -175,12 +175,16 @@ function processDirectory(sourceDir: string, outputDir: string) {
// Grafana root path - navigate up from this script's directory
const basePath = path.resolve(import.meta.dirname, '../../../..');
const sourceDirs = [
path.join(basePath, 'pkg/tests/apis/openapi_snapshots'),
path.join(basePath, 'pkg/extensions/apiserver/tests/openapi_snapshots'),
];
const outputDir = path.join(basePath, 'data/openapi');
const oss = {
source: path.join(basePath, 'pkg/tests/apis/openapi_snapshots'),
output: path.join(import.meta.dirname, '../apis'),
};
for (const sourceDir of sourceDirs) {
processDirectory(sourceDir, outputDir);
const enterprise = {
source: path.join(basePath, 'pkg/extensions/apiserver/tests/openapi_snapshots'),
output: path.join(basePath, 'data/openapi'),
};
for (const config of [oss, enterprise]) {
processDirectory(config.source, config.output);
}

View File

@@ -19,7 +19,6 @@ import (
"github.com/grafana/grafana/pkg/registry/apps/annotation"
"github.com/grafana/grafana/pkg/registry/apps/correlations"
"github.com/grafana/grafana/pkg/registry/apps/example"
"github.com/grafana/grafana/pkg/registry/apps/investigations"
"github.com/grafana/grafana/pkg/registry/apps/logsdrilldown"
"github.com/grafana/grafana/pkg/registry/apps/playlist"
"github.com/grafana/grafana/pkg/registry/apps/plugins"
@@ -107,7 +106,6 @@ func ProvideBuilderRunners(
registrar builder.APIRegistrar,
restConfigProvider apiserver.RestConfigProvider,
features featuremgmt.FeatureToggles,
investigationAppProvider *investigations.InvestigationsAppProvider,
grafanaCfg *setting.Cfg,
) (*Service, error) {
cfgWrapper := func(ctx context.Context) (*rest.Config, error) {
@@ -127,11 +125,6 @@ func ProvideBuilderRunners(
var apiGroupRunner *runner.APIGroupRunner
var err error
providers := []app.Provider{}
//nolint:staticcheck // not yet migrated to OpenFeature
if features.IsEnabledGlobally(featuremgmt.FlagInvestigationsBackend) {
logger.Debug("Investigations backend is enabled")
providers = append(providers, investigationAppProvider)
}
apiGroupRunner, err = runner.NewAPIGroupRunner(cfg, providers...)
if err != nil {

View File

@@ -1,38 +0,0 @@
package investigations
import (
"context"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"k8s.io/apiserver/pkg/authorization/authorizer"
)
func GetAuthorizer() authorizer.Authorizer {
return authorizer.AuthorizerFunc(func(
ctx context.Context, attr authorizer.Attributes,
) (authorized authorizer.Decision, reason string, err error) {
if !attr.IsResourceRequest() {
return authorizer.DecisionNoOpinion, "", nil
}
u, err := identity.GetRequester(ctx)
if err != nil {
return authorizer.DecisionDeny, "valid user is required", err
}
p := u.GetPermissions()
if len(p) == 0 {
return authorizer.DecisionDeny, "no permissions", nil
}
_, ok := p[accesscontrol.ActionDatasourcesExplore]
if !ok {
// defer to the default authorizer if datasources:explore is not present
return authorizer.DecisionNoOpinion, "", nil
}
return authorizer.DecisionAllow, "", nil
})
}

View File

@@ -1,87 +0,0 @@
package investigations
import (
"context"
"testing"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/stretchr/testify/assert"
"k8s.io/apiserver/pkg/authorization/authorizer"
)
func TestGetAuthorizer(t *testing.T) {
tests := []struct {
name string
ctx context.Context
attr authorizer.Attributes
expectedDecision authorizer.Decision
expectedReason string
expectedErr error
}{
{
name: "non-resource request",
ctx: context.TODO(),
attr: &mockAttributes{resourceRequest: false},
expectedDecision: authorizer.DecisionNoOpinion,
expectedReason: "",
expectedErr: nil,
},
{
name: "user has datasources:explore permission",
ctx: identity.WithRequester(context.TODO(), &mockUser{permissions: map[string][]string{accesscontrol.ActionDatasourcesExplore: {}}}),
attr: &mockAttributes{resourceRequest: true},
expectedDecision: authorizer.DecisionAllow,
expectedReason: "",
expectedErr: nil,
},
{
name: "user does not have datasources:explore permission",
ctx: identity.WithRequester(context.TODO(), &mockUser{}),
attr: &mockAttributes{resourceRequest: true},
expectedDecision: authorizer.DecisionDeny,
expectedReason: "no permissions",
expectedErr: nil,
},
{
name: "user does not have datasources:explore permission",
ctx: identity.WithRequester(context.TODO(), &mockUser{permissions: map[string][]string{"foo": {}}}),
attr: &mockAttributes{resourceRequest: true},
expectedDecision: authorizer.DecisionNoOpinion,
expectedReason: "",
expectedErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
auth := GetAuthorizer()
decision, reason, err := auth.Authorize(tt.ctx, tt.attr)
assert.Equal(t, tt.expectedDecision, decision)
assert.Equal(t, tt.expectedReason, reason)
assert.Equal(t, tt.expectedErr, err)
})
}
}
type mockAttributes struct {
authorizer.Attributes
resourceRequest bool
}
func (m *mockAttributes) IsResourceRequest() bool {
return m.resourceRequest
}
// Implement other methods of authorizer.Attributes as needed
type mockUser struct {
identity.Requester
permissions map[string][]string
}
func (m *mockUser) GetPermissions() map[string][]string {
return m.permissions
}
// Implement other methods of identity.Requester as needed

View File

@@ -1,33 +0,0 @@
package investigations
import (
"github.com/grafana/grafana-app-sdk/app"
"github.com/grafana/grafana-app-sdk/simple"
"github.com/grafana/grafana/apps/investigations/pkg/apis"
investigationv0alpha1 "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1"
investigationapp "github.com/grafana/grafana/apps/investigations/pkg/app"
"github.com/grafana/grafana/pkg/services/apiserver/builder"
"github.com/grafana/grafana/pkg/services/apiserver/builder/runner"
"github.com/grafana/grafana/pkg/setting"
)
type InvestigationsAppProvider struct {
app.Provider
cfg *setting.Cfg
}
func RegisterApp(
cfg *setting.Cfg,
) *InvestigationsAppProvider {
provider := &InvestigationsAppProvider{
cfg: cfg,
}
appCfg := &runner.AppBuilderConfig{
OpenAPIDefGetter: investigationv0alpha1.GetOpenAPIDefinitions,
ManagedKinds: investigationapp.GetKinds(),
Authorizer: GetAuthorizer(),
AllowedV0Alpha1Resources: []string{builder.AllResourcesAllowed},
}
provider.Provider = simple.NewAppProvider(apis.LocalManifest(), appCfg, investigationapp.New)
return provider
}

View File

@@ -9,7 +9,6 @@ import (
"github.com/grafana/grafana/pkg/registry/apps/annotation"
"github.com/grafana/grafana/pkg/registry/apps/correlations"
"github.com/grafana/grafana/pkg/registry/apps/example"
"github.com/grafana/grafana/pkg/registry/apps/investigations"
"github.com/grafana/grafana/pkg/registry/apps/logsdrilldown"
"github.com/grafana/grafana/pkg/registry/apps/playlist"
"github.com/grafana/grafana/pkg/registry/apps/plugins"
@@ -21,7 +20,6 @@ var WireSet = wire.NewSet(
ProvideAppInstallers,
ProvideBuilderRunners,
playlist.RegisterAppInstaller,
investigations.RegisterApp,
plugins.ProvideAppInstaller,
shorturl.RegisterAppInstaller,
correlations.RegisterAppInstaller,

View File

@@ -84,7 +84,6 @@ import (
"github.com/grafana/grafana/pkg/registry/apps/annotation"
correlations2 "github.com/grafana/grafana/pkg/registry/apps/correlations"
"github.com/grafana/grafana/pkg/registry/apps/example"
"github.com/grafana/grafana/pkg/registry/apps/investigations"
"github.com/grafana/grafana/pkg/registry/apps/logsdrilldown"
"github.com/grafana/grafana/pkg/registry/apps/playlist"
"github.com/grafana/grafana/pkg/registry/apps/plugins"
@@ -848,8 +847,7 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
return nil, err
}
zanzanaReconciler := dualwrite2.ProvideZanzanaReconciler(cfg, featureToggles, zanzanaClient, sqlStore, serverLockService, folderimplService, registerer)
investigationsAppProvider := investigations.RegisterApp(cfg)
appregistryService, err := appregistry.ProvideBuilderRunners(apiserverService, eventualRestConfigProvider, featureToggles, investigationsAppProvider, cfg)
appregistryService, err := appregistry.ProvideBuilderRunners(apiserverService, eventualRestConfigProvider, featureToggles, cfg)
if err != nil {
return nil, err
}
@@ -1511,8 +1509,7 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
return nil, err
}
zanzanaReconciler := dualwrite2.ProvideZanzanaReconciler(cfg, featureToggles, zanzanaClient, sqlStore, serverLockService, folderimplService, registerer)
investigationsAppProvider := investigations.RegisterApp(cfg)
appregistryService, err := appregistry.ProvideBuilderRunners(apiserverService, eventualRestConfigProvider, featureToggles, investigationsAppProvider, cfg)
appregistryService, err := appregistry.ProvideBuilderRunners(apiserverService, eventualRestConfigProvider, featureToggles, cfg)
if err != nil {
return nil, err
}

View File

@@ -1299,13 +1299,6 @@ var (
Owner: grafanaObservabilityLogsSquad,
Expression: "true",
},
{
Name: "investigationsBackend",
Description: "Enable the investigations backend API",
Stage: FeatureStageExperimental,
Owner: grafanaAppPlatformSquad,
Expression: "false",
},
{
Name: "k8SFolderCounts",
Description: "Enable folder's api server counts",

View File

@@ -179,7 +179,6 @@ unifiedStorageSearchUI,experimental,@grafana/search-and-storage,false,false,fals
elasticsearchCrossClusterSearch,GA,@grafana/partner-datasources,false,false,false
unifiedHistory,experimental,@grafana/grafana-search-navigate-organise,false,false,true
lokiLabelNamesQueryApi,GA,@grafana/observability-logs,false,false,false
investigationsBackend,experimental,@grafana/grafana-app-platform-squad,false,false,false
k8SFolderCounts,experimental,@grafana/search-and-storage,false,false,false
k8SFolderMove,experimental,@grafana/search-and-storage,false,false,false
improvedExternalSessionHandlingSAML,GA,@grafana/identity-access-team,false,false,false
1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
179 elasticsearchCrossClusterSearch GA @grafana/partner-datasources false false false
180 unifiedHistory experimental @grafana/grafana-search-navigate-organise false false true
181 lokiLabelNamesQueryApi GA @grafana/observability-logs false false false
investigationsBackend experimental @grafana/grafana-app-platform-squad false false false
182 k8SFolderCounts experimental @grafana/search-and-storage false false false
183 k8SFolderMove experimental @grafana/search-and-storage false false false
184 improvedExternalSessionHandlingSAML GA @grafana/identity-access-team false false false

View File

@@ -539,10 +539,6 @@ const (
// Defaults to using the Loki `/labels` API instead of `/series`
FlagLokiLabelNamesQueryApi = "lokiLabelNamesQueryApi"
// FlagInvestigationsBackend
// Enable the investigations backend API
FlagInvestigationsBackend = "investigationsBackend"
// FlagK8SFolderCounts
// Enable folder&#39;s api server counts
FlagK8SFolderCounts = "k8SFolderCounts"

View File

@@ -1793,7 +1793,8 @@
"metadata": {
"name": "investigationsBackend",
"resourceVersion": "1764664939750",
"creationTimestamp": "2024-12-18T08:31:03Z"
"creationTimestamp": "2024-12-18T08:31:03Z",
"deletionTimestamp": "2025-12-16T16:06:24Z"
},
"spec": {
"description": "Enable the investigations backend API",

View File

@@ -2,14 +2,14 @@ This folder contains a rendered OpenAPI file for each group/version. The “real
## Generating RTK API Clients
The RTK API clients are generated from processed OpenAPI files using the `scripts/process-specs.ts` script. The source files are in `pkg/tests/apis/openapi_snapshots`, and the processed files are stored in the `data/openapi` directory. Spec processing happens as part of `yarn generate-apis` task, but can also be triggered separately (see below).
The RTK API clients are generated from processed OpenAPI files using the `packages/grafana-openapi/src/scripts/process-specs.ts` script. The source files are in `pkg/tests/apis/openapi_snapshots`, and the processed files are stored in the `packages/grafana-openapi/src/apis` directory. Spec processing happens as part of `yarn generate-apis` task, but can also be triggered separately (see below).
To generate or update the RTK API clients:
1. _If generating or updating an RTK client for the first time_, update `scripts/generate-rtk-apis.js` so `schemaFile` points to the processed spec files, for example:
```typescript
'../public/app/features/dashboards/api/endpoints.gen.ts': {
schemaFile: '../data/openapi/dashboard.grafana.app-v0alpha1.json',
schemaFile: 'packages/grafana-openapi/src/apis/dashboard.grafana.app-v0alpha1.json',
},
```
@@ -24,9 +24,9 @@ To generate or update the RTK API clients:
```bash
yarn generate-apis
```
This command generates (or updates) the spec files in the `data/openapi` directory and generates the RTK API clients.
This command generates (or updates) the spec files in the `packages/grafana-openapi/src/apis` directory and generates the RTK API clients.
If you want to process the OpenAPI files without generating the RTK API clients (for example, if you have a separate `generate-rtk-apis` file), run:
```bash
yarn process-specs
yarn workspace @grafana/openapi process-specs
```

View File

@@ -30,7 +30,6 @@ func TestIntegrationOpenAPIs(t *testing.T) {
EnableFeatureToggles: []string{
featuremgmt.FlagQueryService, // Query Library
featuremgmt.FlagProvisioning,
featuremgmt.FlagInvestigationsBackend,
featuremgmt.FlagGrafanaAdvisor,
featuremgmt.FlagKubernetesAlertingRules,
featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, // all datasources
@@ -97,9 +96,6 @@ func TestIntegrationOpenAPIs(t *testing.T) {
}, {
Group: "iam.grafana.app",
Version: "v0alpha1",
}, {
Group: "investigations.grafana.app",
Version: "v0alpha1",
}, {
Group: "advisor.grafana.app",
Version: "v0alpha1",

View File

@@ -26,7 +26,7 @@ const mockDifferentComponent = {
} as ExtensionInfo;
const mockPluginMeta = {
pluginId: 'grafana-investigations-app',
pluginId: 'grafana-assistant-app',
addedComponents: [mockComponent, mockDifferentComponent],
addedLinks: [],
};
@@ -187,7 +187,7 @@ describe('ExtensionSidebarProvider', () => {
it('should only include permitted plugins in available components', () => {
const permittedPluginMeta = {
pluginId: 'grafana-investigations-app',
pluginId: 'grafana-assistant-app',
addedComponents: [mockComponent],
addedLinks: [],
};
@@ -256,7 +256,7 @@ describe('ExtensionSidebarProvider', () => {
// Call it directly with the test event
subscriberFn(
new OpenExtensionSidebarEvent({
pluginId: 'grafana-investigations-app',
pluginId: 'grafana-assistant-app',
componentTitle: 'Test Component',
props: { testProp: 'test value' },
})
@@ -266,7 +266,7 @@ describe('ExtensionSidebarProvider', () => {
expect(screen.getByTestId('is-open')).toHaveTextContent('true');
expect(screen.getByTestId('props')).toHaveTextContent('{"testProp":"test value"}');
const expectedComponentId = JSON.stringify({
pluginId: 'grafana-investigations-app',
pluginId: 'grafana-assistant-app',
componentTitle: 'Test Component',
});
expect(screen.getByTestId('docked-component-id')).toHaveTextContent(expectedComponentId);
@@ -381,7 +381,7 @@ describe('ExtensionSidebarProvider', () => {
subscriberFn(
new ToggleExtensionSidebarEvent({
pluginId: 'grafana-investigations-app',
pluginId: 'grafana-assistant-app',
componentTitle: 'Test Component',
props: { testProp: 'test value' },
})
@@ -392,7 +392,7 @@ describe('ExtensionSidebarProvider', () => {
expect(screen.getByTestId('is-open')).toHaveTextContent('true');
expect(screen.getByTestId('props')).toHaveTextContent('{"testProp":"test value"}');
const expectedComponentId = JSON.stringify({
pluginId: 'grafana-investigations-app',
pluginId: 'grafana-assistant-app',
componentTitle: 'Test Component',
});
expect(screen.getByTestId('docked-component-id')).toHaveTextContent(expectedComponentId);

View File

@@ -11,7 +11,6 @@ import { DEFAULT_EXTENSION_SIDEBAR_WIDTH, MAX_EXTENSION_SIDEBAR_WIDTH } from './
export const EXTENSION_SIDEBAR_DOCKED_LOCAL_STORAGE_KEY = 'grafana.navigation.extensionSidebarDocked';
export const EXTENSION_SIDEBAR_WIDTH_LOCAL_STORAGE_KEY = 'grafana.navigation.extensionSidebarWidth';
const PERMITTED_EXTENSION_SIDEBAR_PLUGINS = [
'grafana-investigations-app',
'grafana-assistant-app',
'grafana-dash-app',
// The docs plugin ID is transitioning from grafana-grafanadocsplugin-app to grafana-pathfinder-app.

View File

@@ -44,7 +44,7 @@ const mockComponent = {
};
const mockPluginMeta = {
pluginId: 'grafana-investigations-app',
pluginId: 'grafana-assistant-app',
addedComponents: [mockComponent],
};
@@ -109,7 +109,7 @@ describe('ExtensionToolbarItem', () => {
it('should render a dropdown menu when multiple components are available', async () => {
const multipleComponentsMeta = {
pluginId: 'grafana-investigations-app',
pluginId: 'grafana-assistant-app',
addedComponents: [
{ ...mockComponent, title: 'Component 1' },
{ ...mockComponent, title: 'Component 2' },
@@ -141,7 +141,7 @@ describe('ExtensionToolbarItem', () => {
it('should show menu items when clicking the dropdown button', async () => {
const multipleComponentsMeta = {
pluginId: 'grafana-investigations-app',
pluginId: 'grafana-assistant-app',
addedComponents: [
{ ...mockComponent, title: 'Component 1' },
{ ...mockComponent, title: 'Component 2' },
@@ -165,7 +165,7 @@ describe('ExtensionToolbarItem', () => {
it('should toggle the sidebar when clicking a menu item', async () => {
const multipleComponentsMeta = {
pluginId: 'grafana-investigations-app',
pluginId: 'grafana-assistant-app',
addedComponents: [
{ ...mockComponent, title: 'Component 1' },
{ ...mockComponent, title: 'Component 2' },
@@ -192,7 +192,7 @@ describe('ExtensionToolbarItem', () => {
it('should close the sidebar when clicking an active menu item', async () => {
const multipleComponentsMeta = {
pluginId: 'grafana-investigations-app',
pluginId: 'grafana-assistant-app',
addedComponents: [
{ ...mockComponent, title: 'Component 1' },
{ ...mockComponent, title: 'Component 2' },
@@ -218,13 +218,13 @@ describe('ExtensionToolbarItem', () => {
it('should render individual buttons when multiple plugins are available', async () => {
const plugin1Meta = {
pluginId: 'grafana-investigations-app',
addedComponents: [{ ...mockComponent, title: 'Investigations' }],
pluginId: 'grafana-assistant-app',
addedComponents: [{ ...mockComponent, title: 'Assistant' }],
};
const plugin2Meta = {
pluginId: 'grafana-assistant-app',
addedComponents: [{ ...mockComponent, title: 'Assistant' }],
pluginId: 'grafana-dash-app',
addedComponents: [{ ...mockComponent, title: 'Dash' }],
};
(usePluginLinks as jest.Mock).mockReturnValue({
@@ -249,7 +249,7 @@ describe('ExtensionToolbarItem', () => {
expect(buttons).toHaveLength(2);
// Each button should have the correct title
expect(buttons[0]).toHaveAttribute('aria-label', 'Open Investigations');
expect(buttons[1]).toHaveAttribute('aria-label', 'Open Assistant');
expect(buttons[0]).toHaveAttribute('aria-label', 'Open Assistant');
expect(buttons[1]).toHaveAttribute('aria-label', 'Open Dash');
});
});

View File

@@ -17,8 +17,6 @@ function getPluginIcon(pluginId?: string): string {
case 'grafana-grafanadocsplugin-app':
case 'grafana-pathfinder-app':
return 'book';
case 'grafana-investigations-app':
return 'eye';
default:
return 'ai-sparkle';
}

View File

@@ -3414,6 +3414,15 @@ __metadata:
languageName: unknown
linkType: soft
"@grafana/openapi@workspace:packages/grafana-openapi":
version: 0.0.0-use.local
resolution: "@grafana/openapi@workspace:packages/grafana-openapi"
dependencies:
openapi-types: "npm:^12.1.3"
prettier: "npm:3.6.2"
languageName: unknown
linkType: soft
"@grafana/plugin-configs@npm:12.4.0-pre, @grafana/plugin-configs@workspace:*, @grafana/plugin-configs@workspace:packages/grafana-plugin-configs":
version: 0.0.0-use.local
resolution: "@grafana/plugin-configs@workspace:packages/grafana-plugin-configs"
@@ -6121,32 +6130,32 @@ __metadata:
languageName: node
linkType: hard
"@openfeature/ofrep-core@npm:^1.0.0":
version: 1.1.0
resolution: "@openfeature/ofrep-core@npm:1.1.0"
"@openfeature/ofrep-core@npm:^2.0.0":
version: 2.0.0
resolution: "@openfeature/ofrep-core@npm:2.0.0"
peerDependencies:
"@openfeature/core": ^1.6.0
checksum: 10/4198f2f1abf974822bf14530a7f514292d8235552d6e61465d29ffe42d092f675e7f56a9e9da5aa7d45dfbd98cc36316efbdaadaf83e8f510f35865612f5f24f
checksum: 10/598656fb35c517fec8abfc4cd8c5a9cb11d4c0f1698e6aa1dd1cf7c42ebb244a9e5be7c8f0fecdc0d2246747b1a51f7e2fe5b84e2f648b23cf40435d2e3dc176
languageName: node
linkType: hard
"@openfeature/ofrep-web-provider@npm:^0.3.3":
version: 0.3.3
resolution: "@openfeature/ofrep-web-provider@npm:0.3.3"
version: 0.3.5
resolution: "@openfeature/ofrep-web-provider@npm:0.3.5"
dependencies:
"@openfeature/ofrep-core": "npm:^1.0.0"
"@openfeature/ofrep-core": "npm:^2.0.0"
peerDependencies:
"@openfeature/web-sdk": ^1.4.0
checksum: 10/85f362e3ebaa9d421be91e4d966284e28850649e417d5db81181960b95ac693c9faa4a0bdc84eeb03fa694a8cd1e1f5d9de9bf0fba62f8e2669f9637836f0884
checksum: 10/699a9d2591e9d5834f02baa3d68972e52d37efed3866e2c06ad5deb071447c68fdd8afdc2e66e9808f7be162358a338f69cb7912fcb70320f7a7bc6abd00d3d6
languageName: node
linkType: hard
"@openfeature/web-sdk@npm:^1.6.1":
version: 1.7.1
resolution: "@openfeature/web-sdk@npm:1.7.1"
version: 1.7.2
resolution: "@openfeature/web-sdk@npm:1.7.2"
peerDependencies:
"@openfeature/core": ^1.9.0
checksum: 10/358cabfddda8bf67a9bd96ce28f0f84a3218416907f8df4f2a58750ee840d164d86a1c859e8c9aa92d132fa28fcf72a0f17ceece798ff8af297d3e1c1e30cdab
checksum: 10/3fc966d0523ca1941b44350d4c8a42c1b74cb035265d3574a2a6b16e87fa9edfb7211ec945b937399badad5de1e771c55ba7ce04d6eb02f265fc5a37e3af9395
languageName: node
linkType: hard