From 6568f3669dce0c2e951a72bfa0833be1d1084838 Mon Sep 17 00:00:00 2001 From: Galen Kistler <109082771+gtk-grafana@users.noreply.github.com> Date: Fri, 10 Jan 2025 10:01:17 -0600 Subject: [PATCH 01/19] Loki Datasource: Don't escape single quotes (#98767) * fix: remove single quote escape --- .../datasource/loki/datasource.test.ts | 13 +++++++--- .../app/plugins/datasource/loki/datasource.ts | 24 ++++--------------- 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/public/app/plugins/datasource/loki/datasource.test.ts b/public/app/plugins/datasource/loki/datasource.test.ts index 1e5158630aa..c650ba4e4e9 100644 --- a/public/app/plugins/datasource/loki/datasource.test.ts +++ b/public/app/plugins/datasource/loki/datasource.test.ts @@ -269,7 +269,7 @@ describe('LokiDatasource', () => { }, ]; expect(ds.applyTemplateVariables(query, {}, adhocFilters).expr).toBe( - 'rate({bar="baz", job="foo", k1=~"v.*", k2=~"v\\\\\'.*"} |= "bar" [5m])' + `rate({bar="baz", job="foo", k1=~"v.*", k2=~"v'.*"} |= "bar" [5m])` ); }); @@ -325,8 +325,15 @@ describe('LokiDatasource', () => { variable = {} as unknown as CustomVariableModel; }); - it('should only escape single quotes', () => { - expect(ds.interpolateQueryExpr("abc'$^*{}[]+?.()|", variable)).toEqual("abc\\\\'$^*{}[]+?.()|"); + it('should not escape', () => { + expect(ds.interpolateQueryExpr("abc'$^*{}[]+?.()|", variable)).toEqual("abc'$^*{}[]+?.()|"); + }); + + it('should not escape single quotes in line filters', () => { + expect(ds.interpolateQueryExpr("|= `abc'$^*{}[]+?.()|`", variable)).toEqual("|= `abc'$^*{}[]+?.()|`"); + expect(ds.interpolateQueryExpr("|~ `abc'$^*{}[]+?.()|`", variable)).toEqual("|~ `abc'$^*{}[]+?.()|`"); + expect(ds.interpolateQueryExpr("!= `abc'$^*{}[]+?.()|`", variable)).toEqual("!= `abc'$^*{}[]+?.()|`"); + expect(ds.interpolateQueryExpr("!~ `abc'$^*{}[]+?.()|`", variable)).toEqual("!~ `abc'$^*{}[]+?.()|`"); }); it('should return a number', () => { diff --git a/public/app/plugins/datasource/loki/datasource.ts b/public/app/plugins/datasource/loki/datasource.ts index 4a436dc4b87..ca87c5de46f 100644 --- a/public/app/plugins/datasource/loki/datasource.ts +++ b/public/app/plugins/datasource/loki/datasource.ts @@ -814,7 +814,7 @@ export class LokiDatasource interpolateQueryExpr(value: any, variable: QueryVariableModel | CustomVariableModel) { // if no multi or include all do not regexEscape if (!variable.multi && !variable.includeAll) { - return lokiRegularEscape(value); + return value; } if (typeof value === 'string') { @@ -1097,13 +1097,8 @@ export class LokiDatasource expr = adhocFilters.reduce((acc: string, filter: { key: string; operator: string; value: string }) => { const { key, operator } = filter; let { value } = filter; - if (isRegexSelector(operator)) { - // Adhoc filters don't support multiselect, therefore if user selects regex operator - // we are going to consider value to be regex filter and use lokiRegularEscape - // that does not escape regex special characters (e.g. .*test.* => .*test.*) - value = lokiRegularEscape(value); - } else { - // Otherwise, we want to escape special characters in value + if (!isRegexSelector(operator)) { + // We want to escape special characters in value for non-regex selectors to match the same char in the log line as the user types in the input value = escapeLabelValueInSelector(value, operator); } return addLabelToQuery(acc, key, operator, value); @@ -1207,20 +1202,9 @@ export class LokiDatasource }; } } - -// NOTE: these two functions are very similar to the escapeLabelValueIn* functions -// in language_utils.ts, but they are not exactly the same algorithm, and we found -// no way to reuse one in the another or vice versa. -export function lokiRegularEscape(value: T) { - if (typeof value === 'string') { - return value.replace(/'/g, "\\\\'"); - } - return value; -} - export function lokiSpecialRegexEscape(value: T) { if (typeof value === 'string') { - return lokiRegularEscape(value.replace(/\\/g, '\\\\\\\\').replace(/[$^*{}\[\]+?.()|]/g, '\\\\$&')); + return value.replace(/\\/g, '\\\\\\\\').replace(/[$^*{}\[\]+?.()|]/g, '\\\\$&'); } return value; } From 1ba9a27f7071b6ebae62c0b887952278e738dffb Mon Sep 17 00:00:00 2001 From: Tom Ratcliffe Date: Fri, 10 Jan 2025 16:26:03 +0000 Subject: [PATCH 02/19] Chore: Update `no-untranslated-strings` to check tooltip and template literals (#98281) --- .betterer.results | 780 +++++++++++++----- .../rules/no-untranslated-strings.cjs | 5 +- 2 files changed, 562 insertions(+), 223 deletions(-) diff --git a/.betterer.results b/.betterer.results index a7a99439bf7..304cee7afcb 100644 --- a/.betterer.results +++ b/.betterer.results @@ -541,6 +541,12 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"] ], + "packages/grafana-ui/src/components/Combobox/ValuePill.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], + "packages/grafana-ui/src/components/ConfirmModal/ConfirmContent.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "packages/grafana-ui/src/components/DataLinks/DataLinkEditor.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], @@ -550,11 +556,19 @@ exports[`better eslint`] = { "packages/grafana-ui/src/components/DataLinks/DataLinkInput.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], + "packages/grafana-ui/src/components/DataLinks/DataLinkSuggestions.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinksInlineEditor.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], + "packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinksListItem.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + ], "packages/grafana-ui/src/components/DataSourceSettings/AlertingSettings.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "packages/grafana-ui/src/components/DataSourceSettings/BasicAuthSettings.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -579,16 +593,23 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "9"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "10"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "11"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "12"] ], "packages/grafana-ui/src/components/DataSourceSettings/HttpProxySettings.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"] ], "packages/grafana-ui/src/components/DataSourceSettings/SecureSocksProxySettings.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "packages/grafana-ui/src/components/DataSourceSettings/TLSAuthSettings.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -616,6 +637,9 @@ exports[`better eslint`] = { "packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], + "packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "packages/grafana-ui/src/components/FileUpload/FileUpload.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], @@ -642,6 +666,9 @@ exports[`better eslint`] = { "packages/grafana-ui/src/components/InfoBox/InfoBox.story.tsx:5381": [ [0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], + "packages/grafana-ui/src/components/InteractiveTable/Expander/index.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "packages/grafana-ui/src/components/JSONFormatter/json_explorer/json_explorer.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] @@ -675,6 +702,12 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"] + ], + "packages/grafana-ui/src/components/Pagination/Pagination.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], @@ -683,7 +716,8 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "1"] ], "packages/grafana-ui/src/components/PanelChrome/PanelMenu.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "packages/grafana-ui/src/components/PanelChrome/index.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] @@ -691,6 +725,9 @@ exports[`better eslint`] = { "packages/grafana-ui/src/components/Segment/SegmentSelect.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], + "packages/grafana-ui/src/components/Select/MultiValue.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "packages/grafana-ui/src/components/Select/SelectBase.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"], @@ -749,6 +786,11 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "1"], [0, 0, 0, "Unexpected any. Specify a different type.", "2"] ], + "packages/grafana-ui/src/components/Table/CellActions.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] + ], "packages/grafana-ui/src/components/Table/Filter.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], @@ -757,7 +799,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "packages/grafana-ui/src/components/Table/FilterPopup.tsx:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "Unexpected any. Specify a different type.", "1"] ], "packages/grafana-ui/src/components/Table/FooterRow.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], @@ -806,12 +849,21 @@ exports[`better eslint`] = { "packages/grafana-ui/src/components/Tags/TagList.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], + "packages/grafana-ui/src/components/TagsInput/TagItem.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "packages/grafana-ui/src/components/Toggletip/Toggletip.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], + "packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "packages/grafana-ui/src/components/UnitPicker/UnitPicker.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], + "packages/grafana-ui/src/components/UsersIndicator/UserIcon.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], @@ -866,7 +918,8 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "0"] ], "packages/grafana-ui/src/options/builder/stacking.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "packages/grafana-ui/src/slate-plugins/braces.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] @@ -942,11 +995,15 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"] ], "public/app/core/components/AccessControl/PermissionListItem.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "public/app/core/components/AccessControl/index.ts:5381": [ [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"] ], + "public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "public/app/core/components/AppChrome/News/NewsContainer.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] @@ -962,11 +1019,15 @@ exports[`better eslint`] = { ], "public/app/core/components/AppChrome/TopBar/SingleTopBar.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] ], "public/app/core/components/Breadcrumbs/Breadcrumbs.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], + "public/app/core/components/CloseButton/CloseButton.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "public/app/core/components/DynamicImports/SafeDynamicImport.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], @@ -998,7 +1059,9 @@ exports[`better eslint`] = { ], "public/app/core/components/Layers/LayerDragDropList.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"] ], "public/app/core/components/Layers/LayerName.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] @@ -1010,9 +1073,18 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], + "public/app/core/components/OptionsUI/color.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "public/app/core/components/OptionsUI/fieldColor.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], + "public/app/core/components/OptionsUI/units.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], + "public/app/core/components/Page/EditableTitle.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "public/app/core/components/PanelTypeFilter/PanelTypeFilter.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] @@ -1035,6 +1107,9 @@ exports[`better eslint`] = { "public/app/core/components/RolePicker/RolePickerSubMenu.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], + "public/app/core/components/RolePickerDrawer/RolePickerBadges.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "public/app/core/components/Select/OldFolderPicker.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], @@ -1206,6 +1281,10 @@ exports[`better eslint`] = { "public/app/features/actions/ActionsInlineEditor.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], + "public/app/features/actions/ActionsListItem.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + ], "public/app/features/actions/ParamsEditor.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], @@ -1310,10 +1389,13 @@ exports[`better eslint`] = { ], "public/app/features/admin/Users/OrgUsersTable.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] ], "public/app/features/admin/Users/UsersTable.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] ], "public/app/features/admin/ldap/LdapConnectionStatus.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] @@ -1328,7 +1410,8 @@ exports[`better eslint`] = { "public/app/features/admin/ldap/LdapSettingsPage.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"] ], "public/app/features/alerting/routes.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] @@ -1374,7 +1457,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] ], "public/app/features/alerting/unified/CloneRuleEditor.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -1421,11 +1505,12 @@ exports[`better eslint`] = { "public/app/features/alerting/unified/RedirectToRuleViewer.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "6"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] ], "public/app/features/alerting/unified/RuleEditor.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -1442,6 +1527,12 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] ], + "public/app/features/alerting/unified/components/AlertLabel.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], + "public/app/features/alerting/unified/components/AlertLabelDropdown.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "public/app/features/alerting/unified/components/AlertLabels.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], @@ -1454,6 +1545,9 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"] ], + "public/app/features/alerting/unified/components/DynamicTable.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "public/app/features/alerting/unified/components/GrafanaAlertmanagerDeliveryWarning.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], @@ -1484,9 +1578,10 @@ exports[`better eslint`] = { ], "public/app/features/alerting/unified/components/Provisioning.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] ], "public/app/features/alerting/unified/components/RuleLocation.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] @@ -1547,7 +1642,9 @@ exports[`better eslint`] = { "public/app/features/alerting/unified/components/contact-points/ContactPointHeader.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"] ], "public/app/features/alerting/unified/components/contact-points/ContactPoints.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -1600,7 +1697,8 @@ exports[`better eslint`] = { ], "public/app/features/alerting/unified/components/contact-points/components/UnusedBadge.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] ], "public/app/features/alerting/unified/components/export/FileExportPreview.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -1638,10 +1736,12 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], "public/app/features/alerting/unified/components/export/GrafanaRuleFolderExporter.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "public/app/features/alerting/unified/components/export/GrafanaRuleGroupExporter.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "public/app/features/alerting/unified/components/export/GrafanaRulesExporter.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] @@ -1651,7 +1751,7 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], [0, 0, 0, "No untranslated strings. Wrap text with ", "7"], @@ -1659,7 +1759,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "9"], [0, 0, 0, "No untranslated strings. Wrap text with ", "10"], [0, 0, 0, "No untranslated strings. Wrap text with ", "11"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "12"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "12"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "13"] ], "public/app/features/alerting/unified/components/extensions/AlertInstanceExtensionPoint.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] @@ -1702,16 +1803,23 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "8"] ], "public/app/features/alerting/unified/components/mute-timings/MuteTimingsTable.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] ], + "public/app/features/alerting/unified/components/notification-policies/AlertGroupsSummary.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] + ], "public/app/features/alerting/unified/components/notification-policies/ContactPointSelector.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] ], "public/app/features/alerting/unified/components/notification-policies/EditDefaultPolicyForm.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -1748,9 +1856,10 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "13"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "14"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "15"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "16"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "16"], [0, 0, 0, "No untranslated strings. Wrap text with ", "17"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "18"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "18"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "19"] ], "public/app/features/alerting/unified/components/notification-policies/Filters.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -1771,7 +1880,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"] ], "public/app/features/alerting/unified/components/notification-policies/PromDurationDocs.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -1845,9 +1955,13 @@ exports[`better eslint`] = { ], "public/app/features/alerting/unified/components/receivers/TemplatesTable.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] ], "public/app/features/alerting/unified/components/receivers/form/ChannelOptions.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], @@ -1857,9 +1971,10 @@ exports[`better eslint`] = { "public/app/features/alerting/unified/components/receivers/form/ChannelSubForm.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] ], "public/app/features/alerting/unified/components/receivers/form/CloudCommonChannelSettings.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -1907,9 +2022,10 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "6"] ], "public/app/features/alerting/unified/components/receivers/form/fields/KeyValueMapInput.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] ], "public/app/features/alerting/unified/components/receivers/form/fields/OptionField.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], @@ -1920,17 +2036,21 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "5"] ], "public/app/features/alerting/unified/components/receivers/form/fields/StringArrayInput.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] ], "public/app/features/alerting/unified/components/receivers/form/fields/SubformArrayField.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"], - [0, 0, 0, "Unexpected any. Specify a different type.", "2"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], + [0, 0, 0, "Unexpected any. Specify a different type.", "3"], + [0, 0, 0, "Unexpected any. Specify a different type.", "4"] ], "public/app/features/alerting/unified/components/receivers/form/fields/SubformField.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"], - [0, 0, 0, "Unexpected any. Specify a different type.", "2"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], + [0, 0, 0, "Unexpected any. Specify a different type.", "2"], + [0, 0, 0, "Unexpected any. Specify a different type.", "3"] ], "public/app/features/alerting/unified/components/receivers/form/fields/TemplateContentAndPreview.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -1940,16 +2060,22 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] ], "public/app/features/alerting/unified/components/rule-editor/AlertRuleNameInput.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "8"] ], "public/app/features/alerting/unified/components/rule-editor/AnnotationKeyInput.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] @@ -2078,10 +2204,11 @@ exports[`better eslint`] = { "public/app/features/alerting/unified/components/rule-editor/QueryWrapper.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"] ], "public/app/features/alerting/unified/components/rule-editor/RecordingRuleEditor.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] @@ -2298,9 +2425,11 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] ], "public/app/features/alerting/unified/components/rules/CloudRules.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] ], "public/app/features/alerting/unified/components/rules/EditRuleGroupModal.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -2353,7 +2482,9 @@ exports[`better eslint`] = { ], "public/app/features/alerting/unified/components/rules/GrafanaRules.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] ], "public/app/features/alerting/unified/components/rules/ReorderRuleGroupModal.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] @@ -2424,7 +2555,14 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] ], "public/app/features/alerting/unified/components/rules/RuleStats.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] ], "public/app/features/alerting/unified/components/rules/RulesGroup.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -2437,14 +2575,23 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "9"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "10"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "11"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "12"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "13"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "14"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "15"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "16"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "17"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "10"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "11"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "12"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "13"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "14"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "15"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "16"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "17"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "18"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "19"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "20"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "21"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "22"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "23"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "24"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "25"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "26"] ], "public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -2515,8 +2662,9 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "9"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "10"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "9"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "10"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "11"] ], "public/app/features/alerting/unified/components/silences/SilenceDetails.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -2550,8 +2698,10 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "7"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "8"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "9"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "10"] ], "public/app/features/alerting/unified/components/silences/SilencesFilter.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], @@ -2565,7 +2715,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"] ], "public/app/features/alerting/unified/home/GettingStarted.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -2647,7 +2798,12 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"] + ], + "public/app/features/alerting/unified/rule-list/RuleList.v1.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], "public/app/features/alerting/unified/rule-list/components/AlertRuleListItem.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] @@ -2756,13 +2912,14 @@ exports[`better eslint`] = { ], "public/app/features/auth-config/AuthDrawer.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "8"] ], "public/app/features/auth-config/AuthProvidersListPage.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -2776,9 +2933,10 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "8"] ], "public/app/features/auth-config/components/ConfigureAuthCTA.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -2870,12 +3028,13 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] ], "public/app/features/connections/tabs/ConnectData/NoAccessModal/NoAccessModal.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"] ], "public/app/features/connections/tabs/ConnectData/NoAccessModal/index.tsx:5381": [ [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"] @@ -2917,7 +3076,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] ], "public/app/features/dashboard-scene/edit-pane/DashboardEditPane.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "public/app/features/dashboard-scene/edit-pane/VizPanelEditPaneBehavior.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -2940,7 +3100,7 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "9"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "9"], [0, 0, 0, "No untranslated strings. Wrap text with ", "10"], [0, 0, 0, "No untranslated strings. Wrap text with ", "11"], [0, 0, 0, "No untranslated strings. Wrap text with ", "12"], @@ -2950,7 +3110,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "16"], [0, 0, 0, "No untranslated strings. Wrap text with ", "17"], [0, 0, 0, "No untranslated strings. Wrap text with ", "18"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "19"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "19"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "20"] ], "public/app/features/dashboard-scene/inspect/HelpWizard/utils.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] @@ -3002,7 +3163,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] ], "public/app/features/dashboard-scene/panel-edit/PanelDataPane/TransformationsDrawer.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] ], "public/app/features/dashboard-scene/panel-edit/PanelEditControls.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -3010,11 +3172,14 @@ exports[`better eslint`] = { ], "public/app/features/dashboard-scene/panel-edit/PanelEditorRenderer.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"] ], "public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] ], "public/app/features/dashboard-scene/panel-edit/PanelVizTypePicker.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -3098,22 +3263,34 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "7"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "8"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "9"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "10"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "11"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "12"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "13"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "14"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "15"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "9"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "10"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "11"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "12"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "13"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "14"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "15"], [0, 0, 0, "No untranslated strings. Wrap text with ", "16"], [0, 0, 0, "No untranslated strings. Wrap text with ", "17"], [0, 0, 0, "No untranslated strings. Wrap text with ", "18"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "19"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "19"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "20"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "21"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "22"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "23"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "24"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "25"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "26"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "27"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "28"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "29"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "30"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "31"] ], "public/app/features/dashboard-scene/scene/PanelLinks.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] @@ -3221,11 +3398,14 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "13"] ], "public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsList.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] ], "public/app/features/dashboard-scene/settings/annotations/index.tsx:5381": [ [0, 0, 0, "Do not re-export imported variable (\`./AnnotationSettingsEdit\`)", "0"], @@ -3247,9 +3427,13 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "12"] ], "public/app/features/dashboard-scene/settings/links/DashboardLinkList.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"] ], "public/app/features/dashboard-scene/settings/variables/VariableEditorForm.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -3271,7 +3455,9 @@ exports[`better eslint`] = { "public/app/features/dashboard-scene/settings/variables/VariableEditorListRow.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"] ], "public/app/features/dashboard-scene/settings/variables/components/AdHocVariableForm.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -3368,15 +3554,17 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] ], "public/app/features/dashboard-scene/settings/version-history/VersionHistoryHeader.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] ], "public/app/features/dashboard-scene/settings/version-history/VersionHistoryTable.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] ], "public/app/features/dashboard-scene/settings/version-history/index.ts:5381": [ [0, 0, 0, "Do not re-export imported variable (\`./HistorySrv\`)", "0"], @@ -3414,6 +3602,10 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "1"], [0, 0, 0, "Do not use any type assertions.", "2"] ], + "public/app/features/dashboard-scene/variables/VariableUsagesButton.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + ], "public/app/features/dashboard/api/ResponseTransformers.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"], @@ -3426,7 +3618,8 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "0"] ], "public/app/features/dashboard/components/AddLibraryPanelWidget/AddLibraryPanelWidget.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "public/app/features/dashboard/components/AddLibraryPanelWidget/index.ts:5381": [ [0, 0, 0, "Do not re-export imported variable (\`./AddLibraryPanelWidget\`)", "0"] @@ -3450,11 +3643,14 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "15"] ], "public/app/features/dashboard/components/AnnotationSettings/AnnotationSettingsList.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] ], "public/app/features/dashboard/components/AnnotationSettings/index.tsx:5381": [ [0, 0, 0, "Do not re-export imported variable (\`./AnnotationSettingsEdit\`)", "0"], @@ -3484,7 +3680,8 @@ exports[`better eslint`] = { [0, 0, 0, "Do not re-export imported variable (\`./DashboardExporter\`)", "0"] ], "public/app/features/dashboard/components/DashNav/DashNav.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "public/app/features/dashboard/components/DashNav/index.ts:5381": [ [0, 0, 0, "Do not re-export imported variable (\`DashNav\`)", "0"] @@ -3544,7 +3741,9 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] ], "public/app/features/dashboard/components/GenAI/MinimalisticPagination.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] ], "public/app/features/dashboard/components/HelpWizard/HelpWizard.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -3555,12 +3754,14 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "8"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "9"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "9"], [0, 0, 0, "No untranslated strings. Wrap text with ", "10"], [0, 0, 0, "No untranslated strings. Wrap text with ", "11"], [0, 0, 0, "No untranslated strings. Wrap text with ", "12"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "13"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "13"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "14"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "15"] ], "public/app/features/dashboard/components/Inspector/PanelInspector.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] @@ -3570,7 +3771,8 @@ exports[`better eslint`] = { [0, 0, 0, "Do not re-export imported variable (\`./LinkSettingsList\`)", "1"] ], "public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx:5381": [ - [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] + [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], @@ -3579,11 +3781,13 @@ exports[`better eslint`] = { "public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] ], "public/app/features/dashboard/components/PanelEditor/OverrideCategoryTitle.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] ], "public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], @@ -3609,7 +3813,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] ], "public/app/features/dashboard/components/PanelEditor/VisualizationButton.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -3749,7 +3954,8 @@ exports[`better eslint`] = { ], "public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "Unexpected any. Specify a different type.", "2"] ], "public/app/features/dashboard/components/SubMenu/SubMenu.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] @@ -3767,7 +3973,9 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"] ], "public/app/features/dashboard/components/TransformationsEditor/TransformationPicker.tsx:5381": [ [0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], @@ -3787,9 +3995,11 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] ], "public/app/features/dashboard/components/VersionHistory/RevertDashboardModal.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -3805,11 +4015,12 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] ], "public/app/features/dashboard/components/VersionHistory/VersionHistoryTable.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] ], "public/app/features/dashboard/components/VersionHistory/useDashboardRestore.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], @@ -3831,7 +4042,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] ], "public/app/features/dashboard/containers/SoloPanelPage.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] ], "public/app/features/dashboard/dashgrid/PanelLinks.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] @@ -3990,7 +4202,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"] ], "public/app/features/datasources/components/ButtonRow.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -3999,11 +4212,12 @@ exports[`better eslint`] = { ], "public/app/features/datasources/components/CloudInfoBox.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"] ], "public/app/features/datasources/components/DashboardsTable.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -4028,8 +4242,14 @@ exports[`better eslint`] = { "public/app/features/datasources/components/DataSourceReadOnlyMessage.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], + "public/app/features/datasources/components/DataSourceTestingStatus.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] + ], "public/app/features/datasources/components/DataSourceTypeCard.tsx:5381": [ - [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "1"] ], "public/app/features/datasources/components/DataSourcesListCard.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -4120,9 +4340,10 @@ exports[`better eslint`] = { "public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] ], "public/app/features/dimensions/editors/URLPickerTab.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] @@ -4136,7 +4357,11 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "8"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "9"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "10"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "11"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "12"] ], "public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.tsx:5381": [ [0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], @@ -4211,14 +4436,16 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], [0, 0, 0, "No untranslated strings. Wrap text with ", "7"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "8"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "8"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "9"] ], "public/app/features/explore/CorrelationUnsavedChangesModal.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] ], "public/app/features/explore/Explore.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -4231,11 +4458,16 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"] ], - "public/app/features/explore/ExploreRunQueryButton.tsx:5381": [ + "public/app/features/explore/ExplorePage.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], + "public/app/features/explore/ExploreRunQueryButton.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + ], "public/app/features/explore/ExploreToolbar.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] ], "public/app/features/explore/FeatureTogglePage.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -4293,6 +4525,9 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] ], + "public/app/features/explore/Logs/LogsTableAvailableFields.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "public/app/features/explore/Logs/LogsTableEmptyFields.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] ], @@ -4308,7 +4543,8 @@ exports[`better eslint`] = { ], "public/app/features/explore/Logs/LogsTableWrap.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] ], "public/app/features/explore/Logs/LogsVolumePanelList.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -4328,11 +4564,17 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] ], "public/app/features/explore/NodeGraph/NodeGraphContainer.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] ], "public/app/features/explore/PrometheusListView/RawListContainer.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] + ], + "public/app/features/explore/PrometheusListView/RawListItem.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], "public/app/features/explore/PrometheusListView/RawListItemAttributes.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -4351,10 +4593,12 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"] ], "public/app/features/explore/QueryLibrary/QueryTemplatesTable/QueryDescriptionCell.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] ], "public/app/features/explore/RichHistory/RichHistoryStarredTab.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] @@ -4411,7 +4655,9 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "12"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "13"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "14"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "15"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "15"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "16"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "17"] ], "public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFiltersTags.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -4422,7 +4668,9 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "9"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "10"] ], "public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/ViewingLayer.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] @@ -4472,6 +4720,12 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] ], + "public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineCollapser.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"] + ], "public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineHeaderRow.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] ], @@ -4485,7 +4739,8 @@ exports[`better eslint`] = { [0, 0, 0, "Do not re-export imported variable (\`../utils/date\`)", "0"] ], "public/app/features/explore/TraceView/components/common/SearchBarInput.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "public/app/features/explore/TraceView/components/demo/trace-generators.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] @@ -4528,7 +4783,9 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"] ], "public/app/features/explore/TraceView/components/types/index.tsx:5381": [ [0, 0, 0, "Do not re-export imported variable (\`../settings/SpanBarSettings\`)", "0"], @@ -4642,7 +4899,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"] ], "public/app/features/expressions/components/Threshold.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -4806,8 +5064,17 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"] ], + "public/app/features/logs/components/LogDetailsBody.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + ], "public/app/features/logs/components/LogDetailsRow.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"] ], "public/app/features/logs/components/LogLabelStats.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -4819,7 +5086,12 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "9"] ], "public/app/features/logs/components/log-context/LogContextButtons.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -4938,8 +5210,10 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] ], "public/app/features/panel/components/PanelPluginError.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] ], "public/app/features/panel/components/PanelRenderer.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -4949,7 +5223,8 @@ exports[`better eslint`] = { ], "public/app/features/panel/components/VizTypePicker/PanelTypeCard.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "2"] ], "public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -4969,9 +5244,10 @@ exports[`better eslint`] = { [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "1"] ], "public/app/features/playlist/PlaylistTableRows.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] ], "public/app/features/playlist/StartModal.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -4996,10 +5272,12 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] ], "public/app/features/plugins/admin/components/Badges/PluginAngularBadge.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "public/app/features/plugins/admin/components/Badges/PluginDeprecatedBadge.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "public/app/features/plugins/admin/components/Badges/PluginDisabledBadge.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] @@ -5041,6 +5319,9 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] ], + "public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "public/app/features/plugins/admin/components/InstallControls/InstallControlsWarning.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], @@ -5105,7 +5386,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] ], "public/app/features/plugins/admin/components/PluginListItem.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] ], "public/app/features/plugins/admin/components/PluginSignatureDetailsBadge.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], @@ -5113,9 +5395,10 @@ exports[`better eslint`] = { ], "public/app/features/plugins/admin/components/PluginUsage.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] ], "public/app/features/plugins/admin/components/SearchField.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] @@ -5270,9 +5553,9 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], [0, 0, 0, "No untranslated strings. Wrap text with ", "7"], [0, 0, 0, "No untranslated strings. Wrap text with ", "8"], [0, 0, 0, "No untranslated strings. Wrap text with ", "9"], @@ -5308,7 +5591,10 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "39"], [0, 0, 0, "No untranslated strings. Wrap text with ", "40"], [0, 0, 0, "No untranslated strings. Wrap text with ", "41"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "42"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "42"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "43"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "44"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "45"] ], "public/app/features/query/state/DashboardQueryRunner/AnnotationsQueryRunner.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] @@ -5395,20 +5681,23 @@ exports[`better eslint`] = { "public/app/features/serviceaccounts/ServiceAccountPage.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "6"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] ], "public/app/features/serviceaccounts/ServiceAccountPermissions.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], "public/app/features/serviceaccounts/ServiceAccountTable.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "3"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] ], "public/app/features/serviceaccounts/ServiceAccountsListPage.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -5446,7 +5735,29 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], "public/app/features/serviceaccounts/components/ServiceAccountTokensTable.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] + ], + "public/app/features/serviceaccounts/components/ServiceAccountsListItem.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"] + ], + "public/app/features/serviceaccounts/state/reducers.ts:5381": [ + [0, 0, 0, "Do not use any type assertions.", "0"] + ], + "public/app/features/support-bundles/SupportBundles.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], @@ -5454,24 +5765,6 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], [0, 0, 0, "No untranslated strings. Wrap text with ", "6"] ], - "public/app/features/serviceaccounts/components/ServiceAccountsListItem.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] - ], - "public/app/features/serviceaccounts/state/reducers.ts:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"] - ], - "public/app/features/support-bundles/SupportBundles.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] - ], "public/app/features/support-bundles/SupportBundlesCreate.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], @@ -5490,17 +5783,22 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], [0, 0, 0, "No untranslated strings. Wrap text with ", "7"], - [0, 0, 0, "Unexpected any. Specify a different type.", "8"], - [0, 0, 0, "Unexpected any. Specify a different type.", "9"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "8"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "9"], + [0, 0, 0, "Unexpected any. Specify a different type.", "10"], + [0, 0, 0, "Unexpected any. Specify a different type.", "11"] ], "public/app/features/teams/TeamList.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] ], "public/app/features/teams/TeamSettings.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -5546,6 +5844,9 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "10"], [0, 0, 0, "Unexpected any. Specify a different type.", "11"] ], + "public/app/features/trails/ActionTabs/MetricOverviewScene.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "public/app/features/trails/Breakdown/AddToFiltersGraphAction.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] ], @@ -5555,13 +5856,15 @@ exports[`better eslint`] = { "public/app/features/trails/Breakdown/LabelBreakdownScene.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"] ], "public/app/features/trails/Breakdown/SearchInput.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], "public/app/features/trails/Breakdown/SortByScene.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "public/app/features/trails/Breakdown/types.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] @@ -5573,7 +5876,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] ], "public/app/features/trails/DataTrailCard.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] ], "public/app/features/trails/DataTrailSettings.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] @@ -5582,8 +5886,11 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] ], "public/app/features/trails/MetricScene.tsx:5381": [ - [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "4"] ], "public/app/features/trails/MetricSelect/MetricSelectScene.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -5600,6 +5907,9 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] ], + "public/app/features/trails/RelatedLogs/RelatedLogsScene.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + ], "public/app/features/trails/TrailStore/utils.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], @@ -5682,7 +5992,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"] ], "public/app/features/transformers/editors/CalculateFieldTransformerEditor/IndexOptionsEditor.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] ], "public/app/features/transformers/editors/CalculateFieldTransformerEditor/ReduceRowOptionsEditor.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], @@ -5727,7 +6038,11 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "9"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "10"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "11"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "12"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "12"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "13"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "14"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "15"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "16"] ], "public/app/features/transformers/editors/EnumMappingEditor.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], @@ -5737,7 +6052,8 @@ exports[`better eslint`] = { ], "public/app/features/transformers/editors/EnumMappingRow.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"] ], "public/app/features/transformers/editors/FilterByNameTransformerEditor.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -5762,9 +6078,10 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "6"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] ], "public/app/features/transformers/editors/GroupByTransformerEditor.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], @@ -5802,7 +6119,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"] ], "public/app/features/transformers/editors/LimitTransformerEditor.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -5814,7 +6132,8 @@ exports[`better eslint`] = { ], "public/app/features/transformers/editors/OrganizeFieldsTransformerEditor.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] ], "public/app/features/transformers/editors/ReduceTransformerEditor.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], @@ -5840,7 +6159,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"] ], "public/app/features/transformers/extractFields/ExtractFieldsTransformerEditor.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], @@ -5854,17 +6174,19 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "9"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "10"], - [0, 0, 0, "Unexpected any. Specify a different type.", "11"], - [0, 0, 0, "Unexpected any. Specify a different type.", "12"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "11"], + [0, 0, 0, "Unexpected any. Specify a different type.", "12"], + [0, 0, 0, "Unexpected any. Specify a different type.", "13"] ], "public/app/features/transformers/extractFields/components/JSONPathEditor.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], [0, 0, 0, "No untranslated strings. Wrap text with ", "4"], [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "6"] + [0, 0, 0, "No untranslated strings. Wrap text with ", "6"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] ], "public/app/features/transformers/extractFields/extractFields.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], @@ -5899,8 +6221,9 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "7"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "8"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "8"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "9"] ], "public/app/features/transformers/lookupGazetteer/FieldLookupTransformerEditor.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], @@ -5916,7 +6239,9 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], - [0, 0, 0, "No untranslated strings. Wrap text with ", "5"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "7"] ], "public/app/features/transformers/prepareTimeSeries/PrepareTimeSeriesEditor.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -5948,7 +6273,8 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"] ], "public/app/features/transformers/spatial/optionsHelper.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], @@ -5966,7 +6292,9 @@ exports[`better eslint`] = { ], "public/app/features/transformers/timeSeriesTable/TimeSeriesTableTransformEditor.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"] ], "public/app/features/users/TokenRevokedModal.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], @@ -6038,10 +6366,12 @@ exports[`better eslint`] = { "public/app/features/variables/editor/VariableEditorListRow.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], - [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "2"], - [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "4"], - [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "5"] + [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "5"], + [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "6"], + [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "7"] ], "public/app/features/variables/editor/getVariableQueryEditor.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], @@ -6066,10 +6396,18 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "5"], [0, 0, 0, "Unexpected any. Specify a different type.", "6"] ], + "public/app/features/variables/inspect/VariableUsagesButton.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + ], "public/app/features/variables/inspect/VariablesDependenciesButton.tsx:5381": [ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] ], + "public/app/features/variables/inspect/VariablesUnknownButton.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"] + ], "public/app/features/variables/inspect/VariablesUnknownTable.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], [0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "1"], diff --git a/packages/grafana-eslint-rules/rules/no-untranslated-strings.cjs b/packages/grafana-eslint-rules/rules/no-untranslated-strings.cjs index f5249608154..4e8737afe6e 100644 --- a/packages/grafana-eslint-rules/rules/no-untranslated-strings.cjs +++ b/packages/grafana-eslint-rules/rules/no-untranslated-strings.cjs @@ -5,7 +5,7 @@ const createRule = ESLintUtils.RuleCreator( (name) => `https://github.com/grafana/grafana/blob/main/packages/grafana-eslint-rules/README.md#${name}` ); -const propsToCheck = ['label', 'description', 'placeholder', 'aria-label', 'title', 'text']; +const propsToCheck = ['label', 'description', 'placeholder', 'aria-label', 'title', 'text', 'tooltip']; const noUntranslatedStrings = createRule({ create(context) { @@ -17,7 +17,8 @@ const noUntranslatedStrings = createRule({ const isUntranslatedProp = (node.value.type === 'Literal' && node.value.value !== '') || - (node.value.type === 'JSXExpressionContainer' && node.value.expression.type === 'Literal'); + (node.value.type === 'JSXExpressionContainer' && + (node.value.expression.type === 'Literal' || node.value.expression.type === 'TemplateLiteral')); if (isUntranslatedProp) { return context.report({ From 2e969686f0afab86772f7922fad8094a04818a71 Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Fri, 10 Jan 2025 16:31:19 +0000 Subject: [PATCH 03/19] Theme: Extract extra theme definitions into their own directory (#98610) extract theme definitions into their own directory --- .../grafana-data/src/themes/createColors.ts | 6 +- .../grafana-data/src/themes/createTheme.ts | 3 +- packages/grafana-data/src/themes/registry.ts | 106 ++++-------------- .../src/themes/themeDefinitions/debug.ts | 70 ++++++++++++ .../src/themes/themeDefinitions/index.ts | 1 + 5 files changed, 100 insertions(+), 86 deletions(-) create mode 100644 packages/grafana-data/src/themes/themeDefinitions/debug.ts create mode 100644 packages/grafana-data/src/themes/themeDefinitions/index.ts diff --git a/packages/grafana-data/src/themes/createColors.ts b/packages/grafana-data/src/themes/createColors.ts index fd8d987a7fa..bffd7e3f9d5 100644 --- a/packages/grafana-data/src/themes/createColors.ts +++ b/packages/grafana-data/src/themes/createColors.ts @@ -277,7 +277,7 @@ export function createColors(colors: ThemeColorsInput): ThemeColors { const getRichColor = ({ color, name }: GetRichColorProps): ThemeRichColor => { color = { ...color, name }; if (!color.main) { - throw new Error(`Missing main color for ${name}`); + color.main = base[name].main; } if (!color.text) { color.text = color.main; @@ -318,7 +318,9 @@ export function createColors(colors: ThemeColorsInput): ThemeColors { ); } +type RichColorNames = 'primary' | 'secondary' | 'info' | 'error' | 'success' | 'warning'; + interface GetRichColorProps { color: Partial; - name: string; + name: RichColorNames; } diff --git a/packages/grafana-data/src/themes/createTheme.ts b/packages/grafana-data/src/themes/createTheme.ts index 428539cfebf..a224f1be11b 100644 --- a/packages/grafana-data/src/themes/createTheme.ts +++ b/packages/grafana-data/src/themes/createTheme.ts @@ -23,6 +23,7 @@ export interface NewThemeOptions { /** @internal */ export function createTheme(options: NewThemeOptions = {}): GrafanaTheme2 { const { + name, colors: colorsInput = {}, spacing: spacingInput = {}, shape: shapeInput = {}, @@ -40,7 +41,7 @@ export function createTheme(options: NewThemeOptions = {}): GrafanaTheme2 { const visualization = createVisualizationColors(colors); const theme = { - name: colors.mode === 'dark' ? 'Dark' : 'Light', + name: (name ?? colors.mode === 'dark') ? 'Dark' : 'Light', isDark: colors.mode === 'dark', isLight: colors.mode === 'light', colors, diff --git a/packages/grafana-data/src/themes/registry.ts b/packages/grafana-data/src/themes/registry.ts index 2bf6e07aff1..240e5b75717 100644 --- a/packages/grafana-data/src/themes/registry.ts +++ b/packages/grafana-data/src/themes/registry.ts @@ -1,7 +1,7 @@ import { Registry, RegistryItem } from '../utils/Registry'; -import { createColors } from './createColors'; import { createTheme } from './createTheme'; +import * as extraThemes from './themeDefinitions'; import { GrafanaTheme2 } from './types'; export interface ThemeRegistryItem extends RegistryItem { @@ -23,104 +23,44 @@ export function getThemeById(id: string): GrafanaTheme2 { * For internal use only */ export function getBuiltInThemes(includeExtras?: boolean) { - return themeRegistry.list().filter((item) => { + const themes = themeRegistry.list().filter((item) => { return includeExtras ? true : !item.isExtra; }); + // sort themes alphabetically, but put built-in themes (default, dark, light, system) first + const sortedThemes = themes.sort((a, b) => { + if (a.isExtra && !b.isExtra) { + return 1; + } else if (!a.isExtra && b.isExtra) { + return -1; + } else { + return a.name.localeCompare(b.name); + } + }); + return sortedThemes; } /** - * There is also a backend list at services/perferences/themes.go + * There is also a backend list at pkg/services/preference/themes.go */ const themeRegistry = new Registry(() => { return [ { id: 'system', name: 'System preference', build: getSystemPreferenceTheme }, { id: 'dark', name: 'Dark', build: () => createTheme({ colors: { mode: 'dark' } }) }, { id: 'light', name: 'Light', build: () => createTheme({ colors: { mode: 'light' } }) }, - { id: 'debug', name: 'Debug', build: createDebug, isExtra: true }, ]; }); +for (const [id, theme] of Object.entries(extraThemes)) { + themeRegistry.register({ + id, + name: theme.name ?? '', + build: () => createTheme(theme), + isExtra: true, + }); +} + function getSystemPreferenceTheme() { const mediaResult = window.matchMedia('(prefers-color-scheme: dark)'); const id = mediaResult.matches ? 'dark' : 'light'; return getThemeById(id); } - -/** - * a very ugly theme that is useful for debugging and checking if the theme is applied correctly - * borders are red, - * backgrounds are blue, - * text is yellow, - * and grafana loves you <3 - * (also corners are rounded, action states (hover, focus, selected) are purple) - */ -function createDebug(): GrafanaTheme2 { - const baseDarkColors = createColors({ - mode: 'dark', - }); - - return createTheme({ - name: 'Debug', - colors: { - mode: 'dark', - background: { - canvas: '#000033', - primary: '#000044', - secondary: '#000055', - }, - text: { - primary: '#bbbb00', - secondary: '#888800', - disabled: '#444400', - link: '#dddd00', - maxContrast: '#ffff00', - }, - border: { - weak: '#ff000044', - medium: '#ff000088', - strong: '#ff0000ff', - }, - primary: { - ...baseDarkColors.primary, - border: '#ff000088', - text: '#cccc00', - contrastText: '#ffff00', - shade: '#9900dd', - }, - secondary: { - ...baseDarkColors.secondary, - border: '#ff000088', - text: '#cccc00', - contrastText: '#ffff00', - shade: '#9900dd', - }, - info: { - ...baseDarkColors.info, - shade: '#9900dd', - }, - warning: { - ...baseDarkColors.warning, - shade: '#9900dd', - }, - success: { - ...baseDarkColors.success, - shade: '#9900dd', - }, - error: { - ...baseDarkColors.error, - shade: '#9900dd', - }, - action: { - hover: '#9900dd', - focus: '#6600aa', - selected: '#440088', - }, - }, - shape: { - borderRadius: 8, - }, - spacing: { - gridSize: 10, - }, - }); -} diff --git a/packages/grafana-data/src/themes/themeDefinitions/debug.ts b/packages/grafana-data/src/themes/themeDefinitions/debug.ts new file mode 100644 index 00000000000..589ca4ce86b --- /dev/null +++ b/packages/grafana-data/src/themes/themeDefinitions/debug.ts @@ -0,0 +1,70 @@ +import { NewThemeOptions } from '../createTheme'; + +/** + * a very ugly theme that is useful for debugging and checking if the theme is applied correctly + * borders are red, + * backgrounds are blue, + * text is yellow, + * and grafana loves you <3 + * (also corners are rounded, action states (hover, focus, selected) are purple) + */ +const debugTheme: NewThemeOptions = { + name: 'Debug', + colors: { + mode: 'dark', + background: { + canvas: '#000033', + primary: '#000044', + secondary: '#000055', + }, + text: { + primary: '#bbbb00', + secondary: '#888800', + disabled: '#444400', + link: '#dddd00', + maxContrast: '#ffff00', + }, + border: { + weak: '#ff000044', + medium: '#ff000088', + strong: '#ff0000ff', + }, + primary: { + border: '#ff000088', + text: '#cccc00', + contrastText: '#ffff00', + shade: '#9900dd', + }, + secondary: { + border: '#ff000088', + text: '#cccc00', + contrastText: '#ffff00', + shade: '#9900dd', + }, + info: { + shade: '#9900dd', + }, + warning: { + shade: '#9900dd', + }, + success: { + shade: '#9900dd', + }, + error: { + shade: '#9900dd', + }, + action: { + hover: '#9900dd', + focus: '#6600aa', + selected: '#440088', + }, + }, + shape: { + borderRadius: 8, + }, + spacing: { + gridSize: 10, + }, +}; + +export default debugTheme; diff --git a/packages/grafana-data/src/themes/themeDefinitions/index.ts b/packages/grafana-data/src/themes/themeDefinitions/index.ts new file mode 100644 index 00000000000..a88efba4add --- /dev/null +++ b/packages/grafana-data/src/themes/themeDefinitions/index.ts @@ -0,0 +1 @@ +export { default as debug } from './debug'; From 5f1005aa4f6a5b2473d500f1c8bf24d021a4ca87 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 16:32:08 +0000 Subject: [PATCH 04/19] Update dependency @formatjs/intl-durationformat to v0.7.2 (#98820) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 86 ++++++++++++++----------------------------------------- 1 file changed, 22 insertions(+), 64 deletions(-) diff --git a/yarn.lock b/yarn.lock index b6e475e36e1..da5dea4ed3a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2723,15 +2723,15 @@ __metadata: languageName: node linkType: hard -"@formatjs/ecma402-abstract@npm:2.3.1": - version: 2.3.1 - resolution: "@formatjs/ecma402-abstract@npm:2.3.1" +"@formatjs/ecma402-abstract@npm:2.3.2": + version: 2.3.2 + resolution: "@formatjs/ecma402-abstract@npm:2.3.2" dependencies: - "@formatjs/fast-memoize": "npm:2.2.5" - "@formatjs/intl-localematcher": "npm:0.5.9" + "@formatjs/fast-memoize": "npm:2.2.6" + "@formatjs/intl-localematcher": "npm:0.5.10" decimal.js: "npm:10" tslib: "npm:2" - checksum: 10/b88814e060a6875994719d9795f79332017ddb8ee6a619e8e5292350ca1b7e98a7634fe7c427b0698228309a62d03381f1c4e4c5b1f00862353d5ace609ed0de + checksum: 10/db31d3d9b36033ea11ec905638ac0c1d2282f5bf53c9c06ee1d0ffd924f4bf64030702c92b56261756c4998dfa6235462689d8eda82d5913f2d7cf636a9416ae languageName: node linkType: hard @@ -2744,12 +2744,12 @@ __metadata: languageName: node linkType: hard -"@formatjs/fast-memoize@npm:2.2.5": - version: 2.2.5 - resolution: "@formatjs/fast-memoize@npm:2.2.5" +"@formatjs/fast-memoize@npm:2.2.6": + version: 2.2.6 + resolution: "@formatjs/fast-memoize@npm:2.2.6" dependencies: tslib: "npm:2" - checksum: 10/1009b9f782c7b8c0530cde86a68d174bc8055bbf3207eb662429016c2f793bef534e950a13d012861826860ec97d0240fd89eda619267a8191270f581c025f1b + checksum: 10/efa5601dddbd94412ee567d5d067dfd206afa2d08553435f6938e69acba3309b83b9b15021cd30550d5fb93817a53b7691098a11a73f621c2d9318efad49fd76 languageName: node linkType: hard @@ -2775,13 +2775,13 @@ __metadata: linkType: hard "@formatjs/intl-durationformat@npm:^0.7.0": - version: 0.7.1 - resolution: "@formatjs/intl-durationformat@npm:0.7.1" + version: 0.7.2 + resolution: "@formatjs/intl-durationformat@npm:0.7.2" dependencies: - "@formatjs/ecma402-abstract": "npm:2.3.1" - "@formatjs/intl-localematcher": "npm:0.5.9" + "@formatjs/ecma402-abstract": "npm:2.3.2" + "@formatjs/intl-localematcher": "npm:0.5.10" tslib: "npm:2" - checksum: 10/cb8b723425241ddf8775a27f61c3dd58e49262a90a03be1eb23c6f9b0549b88d3419734d61ed137c796f486f7411d95ef58f9b7a165a5ce70ada1d0265429cbc + checksum: 10/863784f3ac51779516fa29c87705af6d4f1b32191a2a48172d2ce16a99e385887a5641703a222ca2b1a0d334e1ab2587be5ef65f48c5ae8a16ba55138356a232 languageName: node linkType: hard @@ -2794,12 +2794,12 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl-localematcher@npm:0.5.9": - version: 0.5.9 - resolution: "@formatjs/intl-localematcher@npm:0.5.9" +"@formatjs/intl-localematcher@npm:0.5.10": + version: 0.5.10 + resolution: "@formatjs/intl-localematcher@npm:0.5.10" dependencies: tslib: "npm:2" - checksum: 10/79b0009dc997dab90619bc0c1405bc541c288eeac10eb5f1aef8d6526611fca71de789a4b62efe781c0c2ccafba9f0a1da4088af436b84e439681df9cd657d7c + checksum: 10/119e36974607d5d3586570db93358c1f316c0736b83acc81dce88468435a9519a9e58a5abe6ed3078ffe40d6b4ad4613c6371e2a39cd570c9b6f561372ffb14d languageName: node linkType: hard @@ -19505,16 +19505,7 @@ __metadata: languageName: node linkType: hard -"is-typed-array@npm:^1.1.13, is-typed-array@npm:^1.1.3": - version: 1.1.13 - resolution: "is-typed-array@npm:1.1.13" - dependencies: - which-typed-array: "npm:^1.1.14" - checksum: 10/f850ba08286358b9a11aee6d93d371a45e3c59b5953549ee1c1a9a55ba5c1dd1bd9952488ae194ad8f32a9cf5e79c8fa5f0cc4d78c00720aa0bbcf238b38062d - languageName: node - linkType: hard - -"is-typed-array@npm:^1.1.14, is-typed-array@npm:^1.1.15": +"is-typed-array@npm:^1.1.13, is-typed-array@npm:^1.1.14, is-typed-array@npm:^1.1.15, is-typed-array@npm:^1.1.3": version: 1.1.15 resolution: "is-typed-array@npm:1.1.15" dependencies: @@ -29947,7 +29938,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:5.7.3": +"typescript@npm:5.7.3, typescript@npm:>=2.7, typescript@npm:>=3 < 6, typescript@npm:^5.0.4, typescript@npm:^5.4.5, typescript@npm:^5.5.4": version: 5.7.3 resolution: "typescript@npm:5.7.3" bin: @@ -29957,16 +29948,6 @@ __metadata: languageName: node linkType: hard -"typescript@npm:>=2.7, typescript@npm:>=3 < 6, typescript@npm:^5.0.4, typescript@npm:^5.4.5, typescript@npm:^5.5.4": - version: 5.7.2 - resolution: "typescript@npm:5.7.2" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10/4caa3904df69db9d4a8bedc31bafc1e19ffb7b24fbde2997a1633ae1398d0de5bdbf8daf602ccf3b23faddf1aeeb9b795223a2ed9c9a4fdcaf07bfde114a401a - languageName: node - linkType: hard - "typescript@patch:typescript@npm%3A5.5.4#optional!builtin": version: 5.5.4 resolution: "typescript@patch:typescript@npm%3A5.5.4#optional!builtin::version=5.5.4&hash=379a07" @@ -29977,7 +29958,7 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@npm%3A5.7.3#optional!builtin": +"typescript@patch:typescript@npm%3A5.7.3#optional!builtin, typescript@patch:typescript@npm%3A>=2.7#optional!builtin, typescript@patch:typescript@npm%3A>=3 < 6#optional!builtin, typescript@patch:typescript@npm%3A^5.0.4#optional!builtin, typescript@patch:typescript@npm%3A^5.4.5#optional!builtin, typescript@patch:typescript@npm%3A^5.5.4#optional!builtin": version: 5.7.3 resolution: "typescript@patch:typescript@npm%3A5.7.3#optional!builtin::version=5.7.3&hash=5786d5" bin: @@ -29987,16 +29968,6 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@npm%3A>=2.7#optional!builtin, typescript@patch:typescript@npm%3A>=3 < 6#optional!builtin, typescript@patch:typescript@npm%3A^5.0.4#optional!builtin, typescript@patch:typescript@npm%3A^5.4.5#optional!builtin, typescript@patch:typescript@npm%3A^5.5.4#optional!builtin": - version: 5.7.2 - resolution: "typescript@patch:typescript@npm%3A5.7.2#optional!builtin::version=5.7.2&hash=5786d5" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10/d75ca10141afc64fd3474b41a8b082b640555bed388d237558aed64e5827ddadb48f90932c7f4205883f18f5bcab8b6a739a2cfac95855604b0dfeb34bc2f3eb - languageName: node - linkType: hard - "ua-parser-js@npm:^1.0.32": version: 1.0.33 resolution: "ua-parser-js@npm:1.0.33" @@ -31108,19 +31079,6 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.14": - version: 1.1.15 - resolution: "which-typed-array@npm:1.1.15" - dependencies: - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.7" - for-each: "npm:^0.3.3" - gopd: "npm:^1.0.1" - has-tostringtag: "npm:^1.0.2" - checksum: 10/c3b6a99beadc971baa53c3ee5b749f2b9bdfa3b3b9a70650dd8511a48b61d877288b498d424712e9991d16019633086bd8b5923369460d93463c5825fa36c448 - languageName: node - linkType: hard - "which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.18, which-typed-array@npm:^1.1.2": version: 1.1.18 resolution: "which-typed-array@npm:1.1.18" From 9df20eda7730720a24bad15ab1e424201e327f7e Mon Sep 17 00:00:00 2001 From: Misi Date: Fri, 10 Jan 2025 17:32:49 +0100 Subject: [PATCH 05/19] Docs: Update SAML docs (#98809) * Update feature toggle name in SAML docs * Update SAML docs --- .../configure-security/configure-authentication/saml/index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/saml/index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/saml/index.md index 376c619bab9..0a438b8c727 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/saml/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/saml/index.md @@ -379,7 +379,8 @@ To configure single logout in Grafana: 1. Enable the `single_logout` option in your configuration. 2. Ensure the `name_id_format` matches the format your IdP expects (e.g., `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`). -3. Enable the `improvedExternalSessionHandling` feature toggle for complete NameID and SessionIndex support (Grafana v11.5+). +3. Enable the `improvedExternalSessionHandlingSAML` feature toggle for complete NameID and SessionIndex support (Grafana v11.5+). +4. After enabling the feature, users may need to log in again to establish a new session. #### `NameID` and `SessionIndex` changes in Grafana v11.5 From 345757c3ae1f2016bac08cccab5d4352056768d2 Mon Sep 17 00:00:00 2001 From: xavi <114113189+volcanonoodle@users.noreply.github.com> Date: Fri, 10 Jan 2025 17:37:37 +0100 Subject: [PATCH 06/19] Auth: Fix SAML user IsExternallySynced not being set correctly (#98487) --- pkg/api/admin_users.go | 3 +- pkg/api/admin_users_test.go | 93 ++++++++++----- pkg/api/login.go | 90 +++++++++++++++ pkg/api/login_test.go | 166 +++++++++++++++++++++++++++ pkg/api/org_users.go | 6 +- pkg/api/org_users_test.go | 12 +- pkg/api/password.go | 3 +- pkg/api/user.go | 5 +- pkg/api/user_test.go | 60 +++++++++- pkg/api/utils.go | 2 +- pkg/login/social/social.go | 8 ++ pkg/services/authn/authn.go | 4 + pkg/services/authn/authntest/fake.go | 29 ++++- pkg/services/login/authinfo.go | 70 ----------- pkg/services/login/authinfo_test.go | 131 --------------------- 15 files changed, 432 insertions(+), 250 deletions(-) delete mode 100644 pkg/services/login/authinfo_test.go diff --git a/pkg/api/admin_users.go b/pkg/api/admin_users.go index 6f7ab9dfd98..e9fec12f691 100644 --- a/pkg/api/admin_users.go +++ b/pkg/api/admin_users.go @@ -158,8 +158,7 @@ func (hs *HTTPServer) AdminUpdateUserPermissions(c *contextmodel.ReqContext) res } if authInfo, err := hs.authInfoService.GetAuthInfo(c.Req.Context(), &login.GetAuthInfoQuery{UserId: userID}); err == nil && authInfo != nil { - oauthInfo := hs.SocialService.GetOAuthInfoProvider(authInfo.AuthModule) - if login.IsGrafanaAdminExternallySynced(hs.Cfg, oauthInfo, authInfo.AuthModule) { + if hs.isGrafanaAdminExternallySynced(hs.Cfg, authInfo.AuthModule) { return response.Error(http.StatusForbidden, "Cannot change Grafana Admin role for externally synced user", nil) } } diff --git a/pkg/api/admin_users_test.go b/pkg/api/admin_users_test.go index 0b6011d95e2..52e64aad75f 100644 --- a/pkg/api/admin_users_test.go +++ b/pkg/api/admin_users_test.go @@ -14,10 +14,11 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/db/dbtest" - "github.com/grafana/grafana/pkg/login/social" "github.com/grafana/grafana/pkg/login/social/socialtest" "github.com/grafana/grafana/pkg/services/auth" "github.com/grafana/grafana/pkg/services/auth/authtest" + "github.com/grafana/grafana/pkg/services/authn" + "github.com/grafana/grafana/pkg/services/authn/authntest" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/login" "github.com/grafana/grafana/pkg/services/login/authinfotest" @@ -243,39 +244,72 @@ func Test_AdminUpdateUserPermissions(t *testing.T) { authEnabled bool skipOrgRoleSync bool expectedRespCode int + enabledAuthnClients []string + authnClientConfig authn.SSOClientConfig }{ + // oauth { - name: "Should allow updating an externally synced OAuth user if Grafana Admin role is not synced", - authModule: login.GenericOAuthModule, - authEnabled: true, - allowAssignGrafanaAdmin: false, - skipOrgRoleSync: false, - expectedRespCode: http.StatusOK, + name: "Should allow updating an externally synced OAuth user if Grafana Admin role is not synced", + authModule: login.GenericOAuthModule, + enabledAuthnClients: []string{authn.ClientWithPrefix("generic_oauth")}, + authnClientConfig: &authntest.FakeSSOClientConfig{ + ExpectedIsSkipOrgRoleSyncEnabled: false, + ExpectedIsAllowAssignGrafanaAdminEnabled: false, + }, + expectedRespCode: http.StatusOK, }, { - name: "Should allow updating an externally synced OAuth user if OAuth provider is not enabled", - authModule: login.GenericOAuthModule, - authEnabled: false, - allowAssignGrafanaAdmin: true, - skipOrgRoleSync: false, - expectedRespCode: http.StatusOK, + name: "Should allow updating an externally synced OAuth user if OAuth provider is not enabled", + authModule: login.GenericOAuthModule, + expectedRespCode: http.StatusOK, + enabledAuthnClients: []string{}, + authnClientConfig: &authntest.FakeSSOClientConfig{ + ExpectedIsSkipOrgRoleSyncEnabled: false, + ExpectedIsAllowAssignGrafanaAdminEnabled: true, + }, }, { - name: "Should allow updating an externally synced OAuth user if org roles are not being synced", - authModule: login.GenericOAuthModule, - authEnabled: true, - allowAssignGrafanaAdmin: true, - skipOrgRoleSync: true, - expectedRespCode: http.StatusOK, + name: "Should allow updating an externally synced OAuth user if org roles are not being synced", + authModule: login.GenericOAuthModule, + expectedRespCode: http.StatusOK, + enabledAuthnClients: []string{authn.ClientWithPrefix("generic_oauth")}, + authnClientConfig: &authntest.FakeSSOClientConfig{ + ExpectedIsSkipOrgRoleSyncEnabled: true, + ExpectedIsAllowAssignGrafanaAdminEnabled: true, + }, }, { - name: "Should not allow updating an externally synced OAuth user", - authModule: login.GenericOAuthModule, - authEnabled: true, - allowAssignGrafanaAdmin: true, - skipOrgRoleSync: false, - expectedRespCode: http.StatusForbidden, + name: "Should not allow updating an externally synced OAuth user", + authModule: login.GenericOAuthModule, + expectedRespCode: http.StatusForbidden, + enabledAuthnClients: []string{authn.ClientWithPrefix("generic_oauth")}, + authnClientConfig: &authntest.FakeSSOClientConfig{ + ExpectedIsSkipOrgRoleSyncEnabled: false, + ExpectedIsAllowAssignGrafanaAdminEnabled: true, + }, }, + // saml + { + name: "Should allow updating an externally synced SAML user if org roles are not being synced", + authModule: login.SAMLAuthModule, + expectedRespCode: http.StatusOK, + enabledAuthnClients: []string{authn.ClientSAML}, + authnClientConfig: &authntest.FakeSSOClientConfig{ + ExpectedIsSkipOrgRoleSyncEnabled: true, + ExpectedIsAllowAssignGrafanaAdminEnabled: true, + }, + }, + { + name: "Should not allow updating an externally synced SAML user", + authModule: login.SAMLAuthModule, + expectedRespCode: http.StatusForbidden, + enabledAuthnClients: []string{authn.ClientSAML}, + authnClientConfig: &authntest.FakeSSOClientConfig{ + ExpectedIsSkipOrgRoleSyncEnabled: false, + ExpectedIsAllowAssignGrafanaAdminEnabled: true, + }, + }, + // jwt { name: "Should allow updating an externally synced JWT user if Grafana Admin role is not synced", authModule: login.JWTModule, @@ -316,10 +350,7 @@ func Test_AdminUpdateUserPermissions(t *testing.T) { socialService := &socialtest.FakeSocialService{} cfg := setting.NewCfg() - switch tc.authModule { - case login.GenericOAuthModule: - socialService.ExpectedAuthInfoProvider = &social.OAuthInfo{AllowAssignGrafanaAdmin: tc.allowAssignGrafanaAdmin, Enabled: tc.authEnabled, SkipOrgRoleSync: tc.skipOrgRoleSync} - case login.JWTModule: + if tc.authModule == login.JWTModule { cfg.JWTAuth.Enabled = tc.authEnabled cfg.JWTAuth.SkipOrgRoleSync = tc.skipOrgRoleSync cfg.JWTAuth.AllowAssignGrafanaAdmin = tc.allowAssignGrafanaAdmin @@ -330,6 +361,10 @@ func Test_AdminUpdateUserPermissions(t *testing.T) { authInfoService: authInfoService, SocialService: socialService, userService: usertest.NewUserServiceFake(), + authnService: &authntest.FakeService{ + ExpectedClientConfig: tc.authnClientConfig, + EnabledClients: tc.enabledAuthnClients, + }, } sc := setupScenarioContext(t, "/api/admin/users/1/permissions") diff --git a/pkg/api/login.go b/pkg/api/login.go index 0361b133872..e4bc1f0854e 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -24,6 +24,7 @@ import ( pref "github.com/grafana/grafana/pkg/services/preference" "github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) @@ -402,6 +403,22 @@ func (hs *HTTPServer) samlAutoLoginEnabled() bool { return hs.samlEnabled() && config.IsAutoLoginEnabled() } +func (hs *HTTPServer) samlSkipOrgRoleSyncEnabled() bool { + config, ok := hs.authnService.GetClientConfig(authn.ClientSAML) + if !ok { + return false + } + return hs.samlEnabled() && config.IsSkipOrgRoleSyncEnabled() +} + +func (hs *HTTPServer) samlAllowAssignGrafanaAdminEnabled() bool { + config, ok := hs.authnService.GetClientConfig(authn.ClientSAML) + if !ok { + return false + } + return hs.samlEnabled() && config.IsAllowAssignGrafanaAdminEnabled() +} + func getLoginExternalError(err error) string { var createTokenErr *auth.CreateTokenErr if errors.As(err, &createTokenErr) { @@ -431,3 +448,76 @@ func getFirstPublicErrorMessage(err *errutil.Error) string { return errPublic.Message } + +// isExternalySynced is used to tell if the user roles are externally synced +// true means that the org role sync is handled by Grafana +// Note: currently the users authinfo is overridden each time the user logs in +// https://github.com/grafana/grafana/blob/4181acec72f76df7ad02badce13769bae4a1f840/pkg/services/login/authinfoservice/database/database.go#L61 +// this means that if the user has multiple auth providers and one of them is set to sync org roles +// then isExternallySynced will be true for this one provider and false for the others +func (hs *HTTPServer) isExternallySynced(cfg *setting.Cfg, authModule string) bool { + // provider enabled in config + if !hs.isProviderEnabled(cfg, authModule) { + return false + } + // first check SAML, LDAP and JWT + switch authModule { + case loginservice.SAMLAuthModule: + return !hs.samlSkipOrgRoleSyncEnabled() + case loginservice.LDAPAuthModule: + return !cfg.LDAPSkipOrgRoleSync + case loginservice.JWTModule: + return !cfg.JWTAuth.SkipOrgRoleSync + } + switch authModule { + case loginservice.GoogleAuthModule, loginservice.OktaAuthModule, loginservice.AzureADAuthModule, loginservice.GitLabAuthModule, loginservice.GithubAuthModule, loginservice.GrafanaComAuthModule, loginservice.GenericOAuthModule: + config, ok := hs.authnService.GetClientConfig(oauthModuleToAuthnClient(authModule)) + if !ok { + return false + } + return !config.IsSkipOrgRoleSyncEnabled() + } + return true +} + +// isGrafanaAdminExternallySynced returns true if Grafana server admin role is being managed by an external auth provider, and false otherwise. +// Grafana admin role sync is available for JWT, OAuth providers and LDAP. +// For JWT and OAuth providers there is an additional config option `allow_assign_grafana_admin` that has to be enabled for Grafana Admin role to be synced. +func (hs *HTTPServer) isGrafanaAdminExternallySynced(cfg *setting.Cfg, authModule string) bool { + if !hs.isExternallySynced(cfg, authModule) { + return false + } + + switch authModule { + case loginservice.JWTModule: + return cfg.JWTAuth.AllowAssignGrafanaAdmin + case loginservice.SAMLAuthModule: + return hs.samlAllowAssignGrafanaAdminEnabled() + case loginservice.LDAPAuthModule: + return true + default: + config, ok := hs.authnService.GetClientConfig(oauthModuleToAuthnClient(authModule)) + if !ok { + return false + } + return config.IsAllowAssignGrafanaAdminEnabled() + } +} + +func (hs *HTTPServer) isProviderEnabled(cfg *setting.Cfg, authModule string) bool { + switch authModule { + case loginservice.SAMLAuthModule: + return hs.authnService.IsClientEnabled(authn.ClientSAML) + case loginservice.LDAPAuthModule: + return cfg.LDAPAuthEnabled + case loginservice.JWTModule: + return cfg.JWTAuth.Enabled + case loginservice.GoogleAuthModule, loginservice.OktaAuthModule, loginservice.AzureADAuthModule, loginservice.GitLabAuthModule, loginservice.GithubAuthModule, loginservice.GrafanaComAuthModule, loginservice.GenericOAuthModule: + return hs.authnService.IsClientEnabled(oauthModuleToAuthnClient(authModule)) + } + return false +} + +func oauthModuleToAuthnClient(authModule string) string { + return authn.ClientWithPrefix(strings.TrimPrefix(authModule, "oauth_")) +} diff --git a/pkg/api/login_test.go b/pkg/api/login_test.go index c6dad435ae0..16fffedc2ad 100644 --- a/pkg/api/login_test.go +++ b/pkg/api/login_test.go @@ -688,6 +688,172 @@ func TestLogoutSaml(t *testing.T) { require.Equal(t, 302, sc.resp.Code) } +func TestIsExternallySynced(t *testing.T) { + testcases := []struct { + name string + cfg *setting.Cfg + provider string + enabledAuthnClients []string + authnClientConfig authn.SSOClientConfig + expected bool + }{ + // Same for all of the OAuth providers + { + name: "AzureAD external user should return that it is externally synced", + cfg: &setting.Cfg{}, + provider: loginservice.AzureADAuthModule, + enabledAuthnClients: []string{authn.ClientWithPrefix("azuread")}, + authnClientConfig: &authntest.FakeSSOClientConfig{ + ExpectedIsSkipOrgRoleSyncEnabled: false, + }, + expected: true, + }, + { + name: "AzureAD external user should return that it is not externally synced when org role sync is set", + cfg: &setting.Cfg{}, + provider: loginservice.AzureADAuthModule, + enabledAuthnClients: []string{authn.ClientWithPrefix(strings.TrimPrefix(loginservice.AzureADAuthModule, "oauth_"))}, + authnClientConfig: &authntest.FakeSSOClientConfig{ + ExpectedIsSkipOrgRoleSyncEnabled: true, + }, + expected: false, + }, + { + name: "AzureAD external user should return that it is not externally synced when the provider is not enabled", + cfg: &setting.Cfg{}, + enabledAuthnClients: []string{}, + authnClientConfig: &authntest.FakeSSOClientConfig{ + ExpectedIsSkipOrgRoleSyncEnabled: false, + }, + provider: loginservice.AzureADAuthModule, + expected: false, + }, + // saml + { + name: "SAML synced user should return that it is not externally synced when the provider is disabled", + cfg: &setting.Cfg{}, + provider: loginservice.SAMLAuthModule, + enabledAuthnClients: []string{}, + authnClientConfig: &authntest.FakeSSOClientConfig{ + ExpectedIsSkipOrgRoleSyncEnabled: false, + }, + expected: false, + }, + { + name: "SAML synced user should return that it is externally synced", + cfg: &setting.Cfg{}, + provider: loginservice.SAMLAuthModule, + enabledAuthnClients: []string{authn.ClientSAML}, + authnClientConfig: &authntest.FakeSSOClientConfig{ + ExpectedIsSkipOrgRoleSyncEnabled: false, + }, + expected: true, + }, + { + name: "SAML synced user should return that it is not externally synced when org role sync is set", + cfg: &setting.Cfg{}, + provider: loginservice.SAMLAuthModule, + enabledAuthnClients: []string{authn.ClientSAML}, + authnClientConfig: &authntest.FakeSSOClientConfig{ + ExpectedIsSkipOrgRoleSyncEnabled: true, + }, + expected: false, + }, + // ldap + { + name: "LDAP synced user should return that it is externally synced", + cfg: &setting.Cfg{LDAPAuthEnabled: true, LDAPSkipOrgRoleSync: false}, + provider: loginservice.LDAPAuthModule, + expected: true, + }, + { + name: "LDAP synced user should return that it is not externally synced when org role sync is set", + cfg: &setting.Cfg{LDAPAuthEnabled: true, LDAPSkipOrgRoleSync: true}, + provider: loginservice.LDAPAuthModule, + expected: false, + }, + // jwt + { + name: "JWT synced user should return that it is externally synced", + cfg: &setting.Cfg{JWTAuth: setting.AuthJWTSettings{Enabled: true, SkipOrgRoleSync: false}}, + provider: loginservice.JWTModule, + expected: true, + }, + { + name: "JWT synced user should return that it is not externally synced when org role sync is set", + cfg: &setting.Cfg{JWTAuth: setting.AuthJWTSettings{Enabled: true, SkipOrgRoleSync: true}}, + provider: loginservice.JWTModule, + expected: false, + }, + // IsProvider test + { + name: "If no provider enabled should return false", + cfg: &setting.Cfg{JWTAuth: setting.AuthJWTSettings{Enabled: false, SkipOrgRoleSync: true}}, + provider: loginservice.JWTModule, + expected: false, + }, + } + + for _, tc := range testcases { + hs := &HTTPServer{ + authnService: &authntest.FakeService{ + ExpectedClientConfig: tc.authnClientConfig, + EnabledClients: tc.enabledAuthnClients, + }, + } + + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.expected, hs.isExternallySynced(tc.cfg, tc.provider)) + }) + } +} + +func TestIsProviderEnabled(t *testing.T) { + testcases := []struct { + name string + provider string + enabledAuthnClients []string + expected bool + }{ + { + name: "Github should return true if enabled", + provider: loginservice.GithubAuthModule, + enabledAuthnClients: []string{authn.ClientWithPrefix(strings.TrimPrefix(loginservice.GithubAuthModule, "oauth_"))}, + expected: true, + }, + { + name: "Github should return false if not enabled", + provider: loginservice.GithubAuthModule, + enabledAuthnClients: []string{}, + expected: false, + }, + // saml + { + name: "SAML should return true if enabled", + provider: loginservice.SAMLAuthModule, + enabledAuthnClients: []string{authn.ClientSAML}, + expected: true, + }, + { + name: "SAML should return false if not enabled", + provider: loginservice.SAMLAuthModule, + enabledAuthnClients: []string{}, + expected: false, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + hs := &HTTPServer{ + authnService: &authntest.FakeService{ + EnabledClients: tc.enabledAuthnClients, + }, + } + assert.Equal(t, tc.expected, hs.isProviderEnabled(setting.NewCfg(), tc.provider)) + }) + } +} + type mockSocialService struct { oAuthInfo *social.OAuthInfo oAuthInfos map[string]*social.OAuthInfo diff --git a/pkg/api/org_users.go b/pkg/api/org_users.go index c0671fe3776..1b83b4e3b77 100644 --- a/pkg/api/org_users.go +++ b/pkg/api/org_users.go @@ -339,9 +339,8 @@ func (hs *HTTPServer) searchOrgUsersHelper(c *contextmodel.ReqContext, query *or for i := range filteredUsers { filteredUsers[i].AccessControl = accessControlMetadata[fmt.Sprint(filteredUsers[i].UserID)] if module, ok := modules[filteredUsers[i].UserID]; ok { - oauthInfo := hs.SocialService.GetOAuthInfoProvider(module) filteredUsers[i].AuthLabels = []string{login.GetAuthProviderLabel(module)} - filteredUsers[i].IsExternallySynced = login.IsExternallySynced(hs.Cfg, module, oauthInfo) + filteredUsers[i].IsExternallySynced = hs.isExternallySynced(hs.Cfg, module) } } @@ -428,8 +427,7 @@ func (hs *HTTPServer) updateOrgUserHelper(c *contextmodel.ReqContext, cmd org.Up } } if authInfo != nil && authInfo.AuthModule != "" { - oauthInfo := hs.SocialService.GetOAuthInfoProvider(authInfo.AuthModule) - if login.IsExternallySynced(hs.Cfg, authInfo.AuthModule, oauthInfo) { + if hs.isExternallySynced(hs.Cfg, authInfo.AuthModule) { return response.Err(org.ErrCannotChangeRoleForExternallySyncedUser.Errorf("Cannot change role for externally synced user")) } } diff --git a/pkg/api/org_users_test.go b/pkg/api/org_users_test.go index ea5f4930661..59bb47330d6 100644 --- a/pkg/api/org_users_test.go +++ b/pkg/api/org_users_test.go @@ -9,6 +9,8 @@ import ( "strings" "testing" + "github.com/grafana/grafana/pkg/services/authn" + "github.com/grafana/grafana/pkg/services/authn/authntest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -258,9 +260,17 @@ func TestOrgUsersAPIEndpoint_updateOrgRole(t *testing.T) { server := SetupAPITestServer(t, func(hs *HTTPServer) { hs.Cfg = setting.NewCfg() hs.Cfg.LDAPAuthEnabled = tt.AuthEnabled - if tt.AuthModule == login.LDAPAuthModule { + switch tt.AuthModule { + case login.LDAPAuthModule: hs.Cfg.LDAPAuthEnabled = tt.AuthEnabled hs.Cfg.LDAPSkipOrgRoleSync = tt.SkipOrgRoleSync + case login.GrafanaComAuthModule: + hs.authnService = &authntest.FakeService{ + EnabledClients: []string{authn.ClientWithPrefix("grafana_com")}, + ExpectedClientConfig: &authntest.FakeSSOClientConfig{ + ExpectedIsSkipOrgRoleSyncEnabled: tt.SkipOrgRoleSync, + }, + } } // AuthModule empty means basic auth diff --git a/pkg/api/password.go b/pkg/api/password.go index fb6db45d939..b7adf54eed9 100644 --- a/pkg/api/password.go +++ b/pkg/api/password.go @@ -39,8 +39,7 @@ func (hs *HTTPServer) SendResetPasswordEmail(c *contextmodel.ReqContext) respons getAuthQuery := login.GetAuthInfoQuery{UserId: usr.ID} if authInfo, err := hs.authInfoService.GetAuthInfo(c.Req.Context(), &getAuthQuery); err == nil { - oauthInfo := hs.SocialService.GetOAuthInfoProvider(authInfo.AuthModule) - if login.IsProviderEnabled(hs.Cfg, authInfo.AuthModule, oauthInfo) { + if hs.isProviderEnabled(hs.Cfg, authInfo.AuthModule) { c.Logger.Info("Requested password reset for external user", nil) return response.Error(http.StatusOK, "Email sent", nil) } diff --git a/pkg/api/user.go b/pkg/api/user.go index 8c8fca56d11..f108d137bb2 100644 --- a/pkg/api/user.go +++ b/pkg/api/user.go @@ -86,9 +86,8 @@ func (hs *HTTPServer) getUserUserProfile(c *contextmodel.ReqContext, userID int6 userProfile.AuthLabels = append(userProfile.AuthLabels, authLabel) userProfile.IsExternal = true - oauthInfo := hs.SocialService.GetOAuthInfoProvider(authInfo.AuthModule) - userProfile.IsExternallySynced = login.IsExternallySynced(hs.Cfg, authInfo.AuthModule, oauthInfo) - userProfile.IsGrafanaAdminExternallySynced = login.IsGrafanaAdminExternallySynced(hs.Cfg, oauthInfo, authInfo.AuthModule) + userProfile.IsExternallySynced = hs.isExternallySynced(hs.Cfg, authInfo.AuthModule) + userProfile.IsGrafanaAdminExternallySynced = hs.isGrafanaAdminExternallySynced(hs.Cfg, authInfo.AuthModule) } userProfile.AccessControl = getAccessControlMetadata(c, "global.users:id:", strconv.FormatInt(userID, 10)) diff --git a/pkg/api/user_test.go b/pkg/api/user_test.go index 5e1ec0d112c..3ecf9f752d9 100644 --- a/pkg/api/user_test.go +++ b/pkg/api/user_test.go @@ -10,6 +10,8 @@ import ( "testing" "time" + "github.com/grafana/grafana/pkg/services/authn" + "github.com/grafana/grafana/pkg/services/authn/authntest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/oauth2" @@ -243,6 +245,7 @@ func Test_GetUserByID(t *testing.T) { authEnabled bool skipOrgRoleSync bool expectedIsGrafanaAdminSynced bool + expectedIsExternallySynced bool }{ { name: "Should return IsGrafanaAdminExternallySynced = false for an externally synced OAuth user if Grafana Admin role is not synced", @@ -251,6 +254,7 @@ func Test_GetUserByID(t *testing.T) { allowAssignGrafanaAdmin: false, skipOrgRoleSync: false, expectedIsGrafanaAdminSynced: false, + expectedIsExternallySynced: true, }, { name: "Should return IsGrafanaAdminExternallySynced = false for an externally synced OAuth user if OAuth provider is not enabled", @@ -259,6 +263,7 @@ func Test_GetUserByID(t *testing.T) { allowAssignGrafanaAdmin: true, skipOrgRoleSync: false, expectedIsGrafanaAdminSynced: false, + expectedIsExternallySynced: false, }, { name: "Should return IsGrafanaAdminExternallySynced = false for an externally synced OAuth user if org roles are not being synced", @@ -267,6 +272,7 @@ func Test_GetUserByID(t *testing.T) { allowAssignGrafanaAdmin: true, skipOrgRoleSync: true, expectedIsGrafanaAdminSynced: false, + expectedIsExternallySynced: false, }, { name: "Should return IsGrafanaAdminExternallySynced = true for an externally synced OAuth user", @@ -275,6 +281,7 @@ func Test_GetUserByID(t *testing.T) { allowAssignGrafanaAdmin: true, skipOrgRoleSync: false, expectedIsGrafanaAdminSynced: true, + expectedIsExternallySynced: true, }, { name: "Should return IsGrafanaAdminExternallySynced = false for an externally synced JWT user if Grafana Admin role is not synced", @@ -283,6 +290,7 @@ func Test_GetUserByID(t *testing.T) { allowAssignGrafanaAdmin: false, skipOrgRoleSync: false, expectedIsGrafanaAdminSynced: false, + expectedIsExternallySynced: true, }, { name: "Should return IsGrafanaAdminExternallySynced = false for an externally synced JWT user if JWT provider is not enabled", @@ -291,6 +299,7 @@ func Test_GetUserByID(t *testing.T) { allowAssignGrafanaAdmin: true, skipOrgRoleSync: false, expectedIsGrafanaAdminSynced: false, + expectedIsExternallySynced: false, }, { name: "Should return IsGrafanaAdminExternallySynced = false for an externally synced JWT user if org roles are not being synced", @@ -299,6 +308,7 @@ func Test_GetUserByID(t *testing.T) { allowAssignGrafanaAdmin: true, skipOrgRoleSync: true, expectedIsGrafanaAdminSynced: false, + expectedIsExternallySynced: false, }, { name: "Should return IsGrafanaAdminExternallySynced = true for an externally synced JWT user", @@ -307,6 +317,31 @@ func Test_GetUserByID(t *testing.T) { allowAssignGrafanaAdmin: true, skipOrgRoleSync: false, expectedIsGrafanaAdminSynced: true, + expectedIsExternallySynced: true, + }, + { + name: "Should return IsExternallySynced = true for an externally synced SAML user", + authModule: login.SAMLAuthModule, + authEnabled: true, + skipOrgRoleSync: false, + expectedIsGrafanaAdminSynced: false, + expectedIsExternallySynced: true, + }, + { + name: "Should return IsExternallySynced = false for an externally synced SAML user if SAML provider is not enabled", + authModule: login.SAMLAuthModule, + authEnabled: false, + skipOrgRoleSync: false, + expectedIsGrafanaAdminSynced: false, + expectedIsExternallySynced: false, + }, + { + name: "Should return IsExternallySynced = false for an externally synced SAML user if if org roles are not being synced", + authModule: login.SAMLAuthModule, + authEnabled: true, + skipOrgRoleSync: true, + expectedIsGrafanaAdminSynced: false, + expectedIsExternallySynced: false, }, } for _, tc := range testcases { @@ -315,15 +350,28 @@ func Test_GetUserByID(t *testing.T) { authInfoService := &authinfotest.FakeService{ExpectedUserAuth: userAuth} socialService := &socialtest.FakeSocialService{} userService := &usertest.FakeUserService{ExpectedUserProfileDTO: &user.UserProfileDTO{}} + authnService := &authntest.FakeService{ + ExpectedClientConfig: &authntest.FakeSSOClientConfig{ + ExpectedIsSkipOrgRoleSyncEnabled: tc.skipOrgRoleSync, + ExpectedIsAllowAssignGrafanaAdminEnabled: tc.allowAssignGrafanaAdmin, + }, + EnabledClients: []string{}, + } cfg := setting.NewCfg() switch tc.authModule { case login.GenericOAuthModule: - socialService.ExpectedAuthInfoProvider = &social.OAuthInfo{AllowAssignGrafanaAdmin: tc.allowAssignGrafanaAdmin, Enabled: tc.authEnabled, SkipOrgRoleSync: tc.skipOrgRoleSync} + if tc.authEnabled { + authnService.EnabledClients = []string{authn.ClientWithPrefix("generic_oauth")} + } case login.JWTModule: cfg.JWTAuth.Enabled = tc.authEnabled cfg.JWTAuth.SkipOrgRoleSync = tc.skipOrgRoleSync cfg.JWTAuth.AllowAssignGrafanaAdmin = tc.allowAssignGrafanaAdmin + case login.SAMLAuthModule: + if tc.authEnabled { + authnService.EnabledClients = []string{authn.ClientSAML} + } } hs := &HTTPServer{ @@ -331,6 +379,7 @@ func Test_GetUserByID(t *testing.T) { authInfoService: authInfoService, SocialService: socialService, userService: userService, + authnService: authnService, } sc := setupScenarioContext(t, "/api/users/1") @@ -348,13 +397,13 @@ func Test_GetUserByID(t *testing.T) { require.NoError(t, err) assert.Equal(t, tc.expectedIsGrafanaAdminSynced, resp.IsGrafanaAdminExternallySynced) + assert.Equal(t, tc.expectedIsExternallySynced, resp.IsExternallySynced) }) } } func TestHTTPServer_UpdateUser(t *testing.T) { settings := setting.NewCfg() - settings.SAMLAuthEnabled = true sqlStore := db.InitTestDB(t) hs := &HTTPServer{ @@ -362,6 +411,9 @@ func TestHTTPServer_UpdateUser(t *testing.T) { SQLStore: sqlStore, AccessControl: acmock.New(), SocialService: &socialtest.FakeSocialService{ExpectedAuthInfoProvider: &social.OAuthInfo{Enabled: true}}, + authnService: &authntest.FakeService{ + EnabledClients: []string{authn.ClientSAML}, + }, } updateUserCommand := user.UpdateUserCommand{ @@ -1102,13 +1154,15 @@ func updateUserScenario(t *testing.T, ctx updateUserContext, hs *HTTPServer) { func TestHTTPServer_UpdateSignedInUser(t *testing.T) { settings := setting.NewCfg() sqlStore := db.InitTestDB(t) - settings.SAMLAuthEnabled = true hs := &HTTPServer{ Cfg: settings, SQLStore: sqlStore, AccessControl: acmock.New(), SocialService: &socialtest.FakeSocialService{}, + authnService: &authntest.FakeService{ + EnabledClients: []string{authn.ClientSAML}, + }, } updateUserCommand := user.UpdateUserCommand{ diff --git a/pkg/api/utils.go b/pkg/api/utils.go index f9c648cc2fa..ec21cf3f3a3 100644 --- a/pkg/api/utils.go +++ b/pkg/api/utils.go @@ -49,7 +49,7 @@ func (hs *HTTPServer) isExternalUser(ctx context.Context, userID int64) (bool, e return true, err } - return login.IsProviderEnabled(hs.Cfg, info.AuthModule, hs.SocialService.GetOAuthInfoProvider(info.AuthModule)), nil + return hs.isProviderEnabled(hs.Cfg, info.AuthModule), nil } func ValidateAndNormalizeEmail(email string) (string, error) { diff --git a/pkg/login/social/social.go b/pkg/login/social/social.go index 6eeaba06667..172c8de58a0 100644 --- a/pkg/login/social/social.go +++ b/pkg/login/social/social.go @@ -121,6 +121,14 @@ func (o *OAuthInfo) IsAutoLoginEnabled() bool { return o.AutoLogin } +func (o *OAuthInfo) IsSkipOrgRoleSyncEnabled() bool { + return o.SkipOrgRoleSync +} + +func (o *OAuthInfo) IsAllowAssignGrafanaAdminEnabled() bool { + return o.AllowAssignGrafanaAdmin +} + type BasicUserInfo struct { Id string Name string diff --git a/pkg/services/authn/authn.go b/pkg/services/authn/authn.go index 8ae12fc0de9..e5efc86b749 100644 --- a/pkg/services/authn/authn.go +++ b/pkg/services/authn/authn.go @@ -95,6 +95,10 @@ type SSOClientConfig interface { IsAutoLoginEnabled() bool // IsSingleLogoutEnabled returns true if the client has single logout enabled IsSingleLogoutEnabled() bool + // IsSkipOrgRoleSyncEnabled returns true if the client has enabled skipping org role sync + IsSkipOrgRoleSyncEnabled() bool + // IsAllowAssignGrafanaAdminEnabled returns true if the client has enabled assigning grafana admin + IsAllowAssignGrafanaAdminEnabled() bool } type Service interface { diff --git a/pkg/services/authn/authntest/fake.go b/pkg/services/authn/authntest/fake.go index 60892f99bf0..fc42a91a115 100644 --- a/pkg/services/authn/authntest/fake.go +++ b/pkg/services/authn/authntest/fake.go @@ -11,9 +11,11 @@ import ( var _ authn.SSOClientConfig = new(FakeSSOClientConfig) type FakeSSOClientConfig struct { - ExpectedName string - ExpectedIsAutoLoginEnabled bool - ExpectedIsSingleLogoutEnabled bool + ExpectedName string + ExpectedIsAutoLoginEnabled bool + ExpectedIsSingleLogoutEnabled bool + ExpectedIsSkipOrgRoleSyncEnabled bool + ExpectedIsAllowAssignGrafanaAdminEnabled bool } func (f *FakeSSOClientConfig) GetDisplayName() string { @@ -28,6 +30,14 @@ func (f *FakeSSOClientConfig) IsSingleLogoutEnabled() bool { return f.ExpectedIsSingleLogoutEnabled } +func (f *FakeSSOClientConfig) IsSkipOrgRoleSyncEnabled() bool { + return f.ExpectedIsSkipOrgRoleSyncEnabled +} + +func (f *FakeSSOClientConfig) IsAllowAssignGrafanaAdminEnabled() bool { + return f.ExpectedIsAllowAssignGrafanaAdminEnabled +} + var ( _ authn.Service = new(FakeService) _ authn.IdentitySynchronizer = new(FakeService) @@ -41,6 +51,7 @@ type FakeService struct { ExpectedErrs []error ExpectedIdentities []*authn.Identity CurrentIndex int + EnabledClients []string } func (f *FakeService) Authenticate(ctx context.Context, r *authn.Request) (*authn.Identity, error) { @@ -64,7 +75,17 @@ func (f *FakeService) Authenticate(ctx context.Context, r *authn.Request) (*auth } func (f *FakeService) IsClientEnabled(name string) bool { - return true + // Consider all clients as enabled if EnabledClients is not explicitly set + if f.EnabledClients == nil { + return true + } + // Check if client is in the list of enabled clients + for _, s := range f.EnabledClients { + if s == name { + return true + } + } + return false } func (f *FakeService) GetClientConfig(name string) (authn.SSOClientConfig, bool) { diff --git a/pkg/services/login/authinfo.go b/pkg/services/login/authinfo.go index b13bf360eb5..32c66beef59 100644 --- a/pkg/services/login/authinfo.go +++ b/pkg/services/login/authinfo.go @@ -2,9 +2,6 @@ package login import ( "context" - - "github.com/grafana/grafana/pkg/login/social" - "github.com/grafana/grafana/pkg/setting" ) type AuthInfoService interface { @@ -59,73 +56,6 @@ const ( OktaLabel = "Okta" ) -// IsExternnalySynced is used to tell if the user roles are externally synced -// true means that the org role sync is handled by Grafana -// Note: currently the users authinfo is overridden each time the user logs in -// https://github.com/grafana/grafana/blob/4181acec72f76df7ad02badce13769bae4a1f840/pkg/services/login/authinfoservice/database/database.go#L61 -// this means that if the user has multiple auth providers and one of them is set to sync org roles -// then IsExternallySynced will be true for this one provider and false for the others -func IsExternallySynced(cfg *setting.Cfg, authModule string, oauthInfo *social.OAuthInfo) bool { - // provider enabled in config - if !IsProviderEnabled(cfg, authModule, oauthInfo) { - return false - } - // first check SAML, LDAP and JWT - switch authModule { - case SAMLAuthModule: - return !cfg.SAMLSkipOrgRoleSync - case LDAPAuthModule: - return !cfg.LDAPSkipOrgRoleSync - case JWTModule: - return !cfg.JWTAuth.SkipOrgRoleSync - } - switch authModule { - case GoogleAuthModule, OktaAuthModule, AzureADAuthModule, GitLabAuthModule, GithubAuthModule, GrafanaComAuthModule, GenericOAuthModule: - if oauthInfo == nil { - return false - } - return !oauthInfo.SkipOrgRoleSync - } - return true -} - -// IsGrafanaAdminExternallySynced returns true if Grafana server admin role is being managed by an external auth provider, and false otherwise. -// Grafana admin role sync is available for JWT, OAuth providers and LDAP. -// For JWT and OAuth providers there is an additional config option `allow_assign_grafana_admin` that has to be enabled for Grafana Admin role to be synced. -func IsGrafanaAdminExternallySynced(cfg *setting.Cfg, oauthInfo *social.OAuthInfo, authModule string) bool { - if !IsExternallySynced(cfg, authModule, oauthInfo) { - return false - } - - switch authModule { - case JWTModule: - return cfg.JWTAuth.AllowAssignGrafanaAdmin - case SAMLAuthModule: - return cfg.SAMLRoleValuesGrafanaAdmin != "" - case LDAPAuthModule: - return true - default: - return oauthInfo != nil && oauthInfo.AllowAssignGrafanaAdmin - } -} - -func IsProviderEnabled(cfg *setting.Cfg, authModule string, oauthInfo *social.OAuthInfo) bool { - switch authModule { - case SAMLAuthModule: - return cfg.SAMLAuthEnabled - case LDAPAuthModule: - return cfg.LDAPAuthEnabled - case JWTModule: - return cfg.JWTAuth.Enabled - case GoogleAuthModule, OktaAuthModule, AzureADAuthModule, GitLabAuthModule, GithubAuthModule, GrafanaComAuthModule, GenericOAuthModule: - if oauthInfo == nil { - return false - } - return oauthInfo.Enabled - } - return false -} - // used for frontend to display a more user friendly label func GetAuthProviderLabel(authModule string) string { switch authModule { diff --git a/pkg/services/login/authinfo_test.go b/pkg/services/login/authinfo_test.go deleted file mode 100644 index 53996b6785c..00000000000 --- a/pkg/services/login/authinfo_test.go +++ /dev/null @@ -1,131 +0,0 @@ -package login - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/grafana/grafana/pkg/login/social" - "github.com/grafana/grafana/pkg/setting" -) - -func TestIsExternallySynced(t *testing.T) { - testcases := []struct { - name string - cfg *setting.Cfg - oauthInfo *social.OAuthInfo - provider string - expected bool - }{ - // Same for all of the OAuth providers - { - name: "AzureAD external user should return that it is externally synced", - cfg: &setting.Cfg{}, - oauthInfo: &social.OAuthInfo{Enabled: true, SkipOrgRoleSync: false}, - provider: AzureADAuthModule, - expected: true, - }, - { - name: "AzureAD external user should return that it is not externally synced when org role sync is set", - cfg: &setting.Cfg{}, - oauthInfo: &social.OAuthInfo{Enabled: true, SkipOrgRoleSync: true}, - provider: AzureADAuthModule, - expected: false, - }, - { - name: "AzureAD external user should return that it is not externally synced when the provider is not enabled", - cfg: &setting.Cfg{}, - oauthInfo: &social.OAuthInfo{Enabled: false, SkipOrgRoleSync: false}, - provider: AzureADAuthModule, - expected: false, - }, - { - name: "AzureAD synced user should return that it is not externally synced when the provider is not enabled and nil", - cfg: &setting.Cfg{}, - oauthInfo: nil, - provider: AzureADAuthModule, - expected: false, - }, - // saml - { - name: "SAML synced user should return that it is externally synced", - cfg: &setting.Cfg{SAMLAuthEnabled: true, SAMLSkipOrgRoleSync: false}, - provider: SAMLAuthModule, - expected: true, - }, - { - name: "SAML synced user should return that it is not externally synced when org role sync is set", - cfg: &setting.Cfg{SAMLAuthEnabled: true, SAMLSkipOrgRoleSync: true}, - provider: SAMLAuthModule, - expected: false, - }, - // ldap - { - name: "LDAP synced user should return that it is externally synced", - cfg: &setting.Cfg{LDAPAuthEnabled: true, LDAPSkipOrgRoleSync: false}, - provider: LDAPAuthModule, - expected: true, - }, - { - name: "LDAP synced user should return that it is not externally synced when org role sync is set", - cfg: &setting.Cfg{LDAPAuthEnabled: true, LDAPSkipOrgRoleSync: true}, - provider: LDAPAuthModule, - expected: false, - }, - // jwt - { - name: "JWT synced user should return that it is externally synced", - cfg: &setting.Cfg{JWTAuth: setting.AuthJWTSettings{Enabled: true, SkipOrgRoleSync: false}}, - provider: JWTModule, - expected: true, - }, - { - name: "JWT synced user should return that it is not externally synced when org role sync is set", - cfg: &setting.Cfg{JWTAuth: setting.AuthJWTSettings{Enabled: true, SkipOrgRoleSync: true}}, - provider: JWTModule, - expected: false, - }, - // IsProvider test - { - name: "If no provider enabled should return false", - cfg: &setting.Cfg{JWTAuth: setting.AuthJWTSettings{Enabled: false, SkipOrgRoleSync: true}}, - provider: JWTModule, - expected: false, - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, tc.expected, IsExternallySynced(tc.cfg, tc.provider, tc.oauthInfo)) - }) - } -} - -func TestIsProviderEnabled(t *testing.T) { - testcases := []struct { - name string - oauthInfo *social.OAuthInfo - provider string - expected bool - }{ - // github - { - name: "Github should return true if enabled", - oauthInfo: &social.OAuthInfo{Enabled: true}, - provider: GithubAuthModule, - expected: true, - }, - { - name: "Github should return false if not enabled", - oauthInfo: &social.OAuthInfo{Enabled: false}, - provider: GithubAuthModule, - expected: false, - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, tc.expected, IsProviderEnabled(setting.NewCfg(), tc.provider, tc.oauthInfo)) - }) - } -} From bc7e90bc281a1666a8b80a625427fb351a1c46d8 Mon Sep 17 00:00:00 2001 From: Gabriel MABILLE Date: Fri, 10 Jan 2025 17:41:56 +0100 Subject: [PATCH 07/19] AuthZ: Fix client dial options (#98827) --- pkg/services/authz/client.go | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/pkg/services/authz/client.go b/pkg/services/authz/client.go index 5095706ce8f..c6cf6525803 100644 --- a/pkg/services/authz/client.go +++ b/pkg/services/authz/client.go @@ -130,7 +130,9 @@ func newGrpcLegacyClient(authCfg *Cfg, tracer tracing.Tracer) (authzlib.AccessCh cfg := authzlib.ClientConfig{RemoteAddress: authCfg.remoteAddress} client, err := authzlib.NewClient(&cfg, authzlib.WithGrpcDialOptionsClientOption( - getDialOpts(clientInterceptor, authCfg.allowInsecure)..., + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithUnaryInterceptor(clientInterceptor.UnaryClientInterceptor), + grpc.WithStreamInterceptor(clientInterceptor.StreamClientInterceptor), ), authzlib.WithTracerClientOption(tracer), // TODO: remove this once access tokens are supported on-prem @@ -163,7 +165,9 @@ func newCloudLegacyClient(authCfg *Cfg, tracer tracing.Tracer) (authzlib.AccessC clientCfg := authzlib.ClientConfig{RemoteAddress: authCfg.remoteAddress} client, err := authzlib.NewClient(&clientCfg, authzlib.WithGrpcDialOptionsClientOption( - getDialOpts(clientInterceptor, authCfg.allowInsecure)..., + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithUnaryInterceptor(clientInterceptor.UnaryClientInterceptor), + grpc.WithStreamInterceptor(clientInterceptor.StreamClientInterceptor), ), authzlib.WithTracerClientOption(tracer), ) @@ -173,16 +177,3 @@ func newCloudLegacyClient(authCfg *Cfg, tracer tracing.Tracer) (authzlib.AccessC return client, nil } - -func getDialOpts(interceptor *authnlib.GrpcClientInterceptor, allowInsecure bool) []grpc.DialOption { - dialOpts := []grpc.DialOption{ - grpc.WithUnaryInterceptor(interceptor.UnaryClientInterceptor), - grpc.WithStreamInterceptor(interceptor.StreamClientInterceptor), - } - if allowInsecure { - // allow insecure connections in development mode to facilitate testing - dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials())) - } - - return dialOpts -} From d7da75c480dfd4844063efa201b9e34151251c9b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 17:16:41 +0000 Subject: [PATCH 08/19] Update dependency @grafana/plugin-e2e to v1.14.6 (#98830) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index da5dea4ed3a..019f8b7d4ad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3606,16 +3606,16 @@ __metadata: linkType: soft "@grafana/plugin-e2e@npm:^1.11.0": - version: 1.14.1 - resolution: "@grafana/plugin-e2e@npm:1.14.1" + version: 1.14.6 + resolution: "@grafana/plugin-e2e@npm:1.14.6" dependencies: - "@grafana/e2e-selectors": "npm:^11.5.0-214310" + "@grafana/e2e-selectors": "npm:^11.5.0-216287" semver: "npm:^7.5.4" uuid: "npm:^11.0.2" yaml: "npm:^2.3.4" peerDependencies: "@playwright/test": ^1.41.2 - checksum: 10/bd2a1688ab5d49668cd72102e91107f84a9f8dfcddbd5ca3cd2a551a5219870c50c73355f8e3a599190c1f341680d1bb6f13a3cdeb84c69cfa6ba061ff7af59f + checksum: 10/5a8c80be80c377a27eff6a20b6677a1a24529716de404c36da65c16bdf88927fecf3992d10370bc2d90ee30057740c8ebefed698c0d649d3972b99b4e0a5c53f languageName: node linkType: hard From aaa4fe1fe4ab3db955abb093a6d4cf8b4428257c Mon Sep 17 00:00:00 2001 From: Alexander Akhmetov Date: Fri, 10 Jan 2025 18:36:05 +0100 Subject: [PATCH 09/19] Alerting: handle err-mimir-label-value-too-long as user error in the prom writer (#98783) Alerting: handle err-mimir-label-value-too-long as user error in the writer --- pkg/services/ngalert/writer/prom.go | 5 +++++ pkg/services/ngalert/writer/prom_test.go | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/pkg/services/ngalert/writer/prom.go b/pkg/services/ngalert/writer/prom.go index 15f768e7c67..9778d2f824b 100644 --- a/pkg/services/ngalert/writer/prom.go +++ b/pkg/services/ngalert/writer/prom.go @@ -28,6 +28,7 @@ const ( MimirDuplicateTimestampError = "err-mimir-sample-duplicate-timestamp" MimirInvalidLabelError = "err-mimir-label-invalid" MimirMaxSeriesPerUserError = "err-mimir-max-series-per-user" + MimirLabelValueTooLongError = "err-mimir-label-value-too-long" // Best effort error messages PrometheusDuplicateTimestampError = "duplicate sample for timestamp" @@ -275,6 +276,10 @@ func checkWriteError(writeErr promremote.WriteError) (err error, ignored bool) { return errors.Join(ErrRejectedWrite, writeErr), false } + if strings.Contains(msg, MimirLabelValueTooLongError) { + return errors.Join(ErrRejectedWrite, writeErr), false + } + // For now, all 400s that are not previously known are considered unexpected. // TODO: Consider blanket-converting all 400s to be known errors. This should only be done once we are confident this is not a problem with this client. return errors.Join(ErrUnexpectedWriteFailure, writeErr), false diff --git a/pkg/services/ngalert/writer/prom_test.go b/pkg/services/ngalert/writer/prom_test.go index c2e61a6df39..af5bd5e9f29 100644 --- a/pkg/services/ngalert/writer/prom_test.go +++ b/pkg/services/ngalert/writer/prom_test.go @@ -238,6 +238,22 @@ func TestPrometheusWriter_Write(t *testing.T) { require.Error(t, err) require.ErrorIs(t, err, ErrRejectedWrite) }) + + t.Run("too long labels fit under the client error category", func(t *testing.T) { + msg := "received a series whose label value length exceeds the limit, label: 'label-1', value: 'value-1' (truncated) series: 'some_series (err-mimir-label-value-too-long). To adjust the related per-tenant limit, configure -validation.max-length-label-value, or contact your service administrator." + clientErr := testClientWriteError{ + statusCode: http.StatusBadRequest, + msg: &msg, + } + client.writeSeriesFunc = func(ctx context.Context, ts promremote.TSList, opts promremote.WriteOptions) (promremote.WriteResult, promremote.WriteError) { + return promremote.WriteResult{}, clientErr + } + + err := writer.Write(ctx, "test", now, frames, 1, map[string]string{"extra": "label"}) + + require.Error(t, err) + require.ErrorIs(t, err, ErrRejectedWrite) + }) } func extractValue(t *testing.T, frames data.Frames, labels map[string]string, frameType data.FrameType) float64 { From 90e65f6ce6ba86506c54bbffdcf15a77d852a450 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 17:48:16 +0000 Subject: [PATCH 10/19] Update dependency @rsdoctor/webpack-plugin to v0.4.13 (#98833) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 96 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/yarn.lock b/yarn.lock index 019f8b7d4ad..65cfefdf4e6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6817,21 +6817,21 @@ __metadata: languageName: node linkType: hard -"@rsdoctor/client@npm:0.4.12": - version: 0.4.12 - resolution: "@rsdoctor/client@npm:0.4.12" - checksum: 10/04ae4f8de34fdf5cec5b9db2072e646f3327a7ba7ca4a96942961fa26129e715db92c28ca68bf0f6c5149ccbfb9b73aa2d2984242bf8d35bc54f827e2ccae84e +"@rsdoctor/client@npm:0.4.13": + version: 0.4.13 + resolution: "@rsdoctor/client@npm:0.4.13" + checksum: 10/6eaa768eceedf76aa940fcb5980eb39f5960f4f341c13c96ecddac8abb456c8248497dfbc0d7de933d02ad837f761af93bc54d76e84dca45591a6d99f000556b languageName: node linkType: hard -"@rsdoctor/core@npm:0.4.12": - version: 0.4.12 - resolution: "@rsdoctor/core@npm:0.4.12" +"@rsdoctor/core@npm:0.4.13": + version: 0.4.13 + resolution: "@rsdoctor/core@npm:0.4.13" dependencies: - "@rsdoctor/graph": "npm:0.4.12" - "@rsdoctor/sdk": "npm:0.4.12" - "@rsdoctor/types": "npm:0.4.12" - "@rsdoctor/utils": "npm:0.4.12" + "@rsdoctor/graph": "npm:0.4.13" + "@rsdoctor/sdk": "npm:0.4.13" + "@rsdoctor/types": "npm:0.4.13" + "@rsdoctor/utils": "npm:0.4.13" axios: "npm:^1.7.9" enhanced-resolve: "npm:5.12.0" filesize: "npm:^10.1.6" @@ -6841,31 +6841,31 @@ __metadata: semver: "npm:^7.6.3" source-map: "npm:^0.7.4" webpack-bundle-analyzer: "npm:^4.10.2" - checksum: 10/d77252288cec3ad9cd6389fb772125fcbdca669c0186a540a9270f2c3ac01b0620d188595e952a3683b0af4e4eef2c8816b0af71a2d87667eef7f2e47484a4b3 + checksum: 10/c105de8a0933ec7abf2104762a7db1046f0bd2c418fc67fad8315c44f22cdb5a6ec34dbcf5da24c8a698959d475f120cc598ec012870fe757fc968fbe603ced3 languageName: node linkType: hard -"@rsdoctor/graph@npm:0.4.12": - version: 0.4.12 - resolution: "@rsdoctor/graph@npm:0.4.12" +"@rsdoctor/graph@npm:0.4.13": + version: 0.4.13 + resolution: "@rsdoctor/graph@npm:0.4.13" dependencies: - "@rsdoctor/types": "npm:0.4.12" - "@rsdoctor/utils": "npm:0.4.12" - lodash: "npm:^4.17.21" + "@rsdoctor/types": "npm:0.4.13" + "@rsdoctor/utils": "npm:0.4.13" + lodash.unionby: "npm:^4.8.0" socket.io: "npm:4.8.1" source-map: "npm:^0.7.4" - checksum: 10/53cb9dd4c8507cf22ee6088e4fc1b5d26fb2090dee1570fd1964659d854bab33ed7ca73862a84a256280a85aa076c5e18953830af2127fb583d5eaa5274a934d + checksum: 10/40080b9726661d51bbec931ec85376039eec9f02c6a5523eb78365dbe0c7d2f86798fa2ff7ca29c13e844c5ab686bd8b6947d064aa0caaa97b06754f8a167ea1 languageName: node linkType: hard -"@rsdoctor/sdk@npm:0.4.12": - version: 0.4.12 - resolution: "@rsdoctor/sdk@npm:0.4.12" +"@rsdoctor/sdk@npm:0.4.13": + version: 0.4.13 + resolution: "@rsdoctor/sdk@npm:0.4.13" dependencies: - "@rsdoctor/client": "npm:0.4.12" - "@rsdoctor/graph": "npm:0.4.12" - "@rsdoctor/types": "npm:0.4.12" - "@rsdoctor/utils": "npm:0.4.12" + "@rsdoctor/client": "npm:0.4.13" + "@rsdoctor/graph": "npm:0.4.13" + "@rsdoctor/types": "npm:0.4.13" + "@rsdoctor/utils": "npm:0.4.13" "@types/fs-extra": "npm:^11.0.4" body-parser: "npm:1.20.3" cors: "npm:2.8.5" @@ -6878,13 +6878,13 @@ __metadata: socket.io: "npm:4.8.1" source-map: "npm:^0.7.4" tapable: "npm:2.2.1" - checksum: 10/a0f20c0410e44fd9f7428fee39c45abf493144e73aa910d9c8f34760461d36d1144856c9ea3078afee2282817acb8bffb82bad9ec8443279dde5bf14875df495 + checksum: 10/017cfe877952038a573d6e498dc4c5da1b0754bd5e50ccaf02e5263581a3ca901600b77b59cd9556cc9baefef8c37b0ccf5e7364342fb080c14e4b72d6005e97 languageName: node linkType: hard -"@rsdoctor/types@npm:0.4.12": - version: 0.4.12 - resolution: "@rsdoctor/types@npm:0.4.12" +"@rsdoctor/types@npm:0.4.13": + version: 0.4.13 + resolution: "@rsdoctor/types@npm:0.4.13" dependencies: "@types/connect": "npm:3.4.38" "@types/estree": "npm:1.0.5" @@ -6896,16 +6896,16 @@ __metadata: peerDependenciesMeta: "@rspack/core": optional: true - checksum: 10/41cbfd7eb36999e79eed49ebc49e5665c5c8c68070f2981558cdf110fdcc60d97b2e653ead5c12cf9ebcef8b7de98b42bc20cf15258a42a3f2ae5a7b75aa8379 + checksum: 10/a6e51bfc9e88779e9043d6f75420604f2839bbd7f7608a58556374ae74e7191b9a47872f9a426cf76e2e7756c8724550237398e093a415f6b8fbab84fae2dde5 languageName: node linkType: hard -"@rsdoctor/utils@npm:0.4.12": - version: 0.4.12 - resolution: "@rsdoctor/utils@npm:0.4.12" +"@rsdoctor/utils@npm:0.4.13": + version: 0.4.13 + resolution: "@rsdoctor/utils@npm:0.4.13" dependencies: "@babel/code-frame": "npm:7.25.7" - "@rsdoctor/types": "npm:0.4.12" + "@rsdoctor/types": "npm:0.4.13" "@types/estree": "npm:1.0.5" acorn: "npm:^8.10.0" acorn-import-assertions: "npm:1.9.0" @@ -6919,27 +6919,26 @@ __metadata: get-port: "npm:5.1.1" json-stream-stringify: "npm:3.0.1" lines-and-columns: "npm:2.0.4" - lodash: "npm:^4.17.21" rslog: "npm:^1.2.3" strip-ansi: "npm:^6.0.1" - checksum: 10/f0640c4cabacbf0c65cb2c2bc36791c9f07c9e4ea7917636f5480c193043a7f16cf276734a91bcd9309ec3389987e586e3a557e99266d758affdb76a2efb6a5a + checksum: 10/e102670b4432ee0ed47cda15eef8fc90e703451f3d8c7efe8d7e4817fe92b2702b33a303b156fd5409d6abcc0c5712be3a81817dd21f09dd9a6bec5ecf1c72ef languageName: node linkType: hard "@rsdoctor/webpack-plugin@npm:^0.4.6": - version: 0.4.12 - resolution: "@rsdoctor/webpack-plugin@npm:0.4.12" + version: 0.4.13 + resolution: "@rsdoctor/webpack-plugin@npm:0.4.13" dependencies: - "@rsdoctor/core": "npm:0.4.12" - "@rsdoctor/graph": "npm:0.4.12" - "@rsdoctor/sdk": "npm:0.4.12" - "@rsdoctor/types": "npm:0.4.12" - "@rsdoctor/utils": "npm:0.4.12" + "@rsdoctor/core": "npm:0.4.13" + "@rsdoctor/graph": "npm:0.4.13" + "@rsdoctor/sdk": "npm:0.4.13" + "@rsdoctor/types": "npm:0.4.13" + "@rsdoctor/utils": "npm:0.4.13" fs-extra: "npm:^11.1.1" lodash: "npm:^4.17.21" peerDependencies: webpack: 5.x - checksum: 10/e2bfc961f39bfa27e60ada29cccf2734db59062d78007cedaec3c794f8c39864c6f0e487879f565fcad100ec970d3e320c5927315fc2ed00d55a00924891b6f3 + checksum: 10/f244ef8f1b28192cb766d66099e6999ba5a042d19bd1ab29f023f4844807a6a444e26a73b31a077e03c600979d5f10ec70fd1a42e9af9766b6f22241f124b990 languageName: node linkType: hard @@ -21339,6 +21338,13 @@ __metadata: languageName: node linkType: hard +"lodash.unionby@npm:^4.8.0": + version: 4.8.0 + resolution: "lodash.unionby@npm:4.8.0" + checksum: 10/246eaf5b24cb63387abfbaab3a23883c500c56eb0d4b364c48739873b55a3c3131688f35926de64046b74377937ddb344a84282ebc0528b9dc3be5866216a91e + languageName: node + linkType: hard + "lodash.uniq@npm:^4.5.0": version: 4.5.0 resolution: "lodash.uniq@npm:4.5.0" From 3eace5f7c8fb1f216699b2e202cc88e5e44cc889 Mon Sep 17 00:00:00 2001 From: Matias Chomicki Date: Fri, 10 Jan 2025 17:59:03 +0000 Subject: [PATCH 11/19] Loki: Sync query direction with sort order in Explore and Dashboards (#98722) * Logs: sync direction and sort order for loki queries in explore * Logs: emit event on sort order change * Loki query editor: listen to sort change events and update direction * Loki query editor: unsubscribe to sort event * Logs: don't publish events in Explore * LokiQueryBuilderOptions: use stored order as default value when in explore * Query builder options: initialize query direction * Logs: unit test * LogsPanel: update unit test * Update tests * LokiQueryBuilderOptions: unit test * Update public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx Co-authored-by: Galen Kistler <109082771+gtk-grafana@users.noreply.github.com> * Update public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx --------- Co-authored-by: Galen Kistler <109082771+gtk-grafana@users.noreply.github.com> --- packages/grafana-data/src/index.ts | 2 + packages/grafana-data/src/types/logs.ts | 12 +- .../app/features/explore/Logs/Logs.test.tsx | 33 +++++ public/app/features/explore/Logs/Logs.tsx | 27 ++++ .../loki/components/LokiQueryEditor.test.tsx | 3 + .../components/LokiQueryEditorByApp.test.tsx | 7 + .../MonacoFieldWrapper.test.tsx | 7 + .../LokiQueryBuilderOptions.test.tsx | 121 +++++++++++++++++- .../components/LokiQueryBuilderOptions.tsx | 79 ++++++++++-- .../app/plugins/panel/logs/LogsPanel.test.tsx | 58 ++++++++- public/app/plugins/panel/logs/LogsPanel.tsx | 13 +- 11 files changed, 340 insertions(+), 22 deletions(-) diff --git a/packages/grafana-data/src/index.ts b/packages/grafana-data/src/index.ts index d6d414a81c5..76195d7d8c0 100644 --- a/packages/grafana-data/src/index.ts +++ b/packages/grafana-data/src/index.ts @@ -764,6 +764,8 @@ export { type DataSourceWithQueryModificationSupport, hasToggleableQueryFiltersSupport, hasQueryModificationSupport, + LogSortOrderChangeEvent, + type LogSortOrderChangePayload, } from './types/logs'; export { type AnnotationQuery, diff --git a/packages/grafana-data/src/types/logs.ts b/packages/grafana-data/src/types/logs.ts index 86df7bde61f..67a194202a7 100644 --- a/packages/grafana-data/src/types/logs.ts +++ b/packages/grafana-data/src/types/logs.ts @@ -1,6 +1,8 @@ import { Observable } from 'rxjs'; -import { DataQuery } from '@grafana/schema'; +import { DataQuery, LogsSortOrder } from '@grafana/schema'; + +import { BusEventWithPayload } from '../events/types'; import { KeyValue, Labels } from './data'; import { DataFrame } from './dataFrame'; @@ -366,3 +368,11 @@ export const hasQueryModificationSupport = ( 'getSupportedQueryModifications' in datasource ); }; + +export interface LogSortOrderChangePayload { + order: LogsSortOrder; +} + +export class LogSortOrderChangeEvent extends BusEventWithPayload { + static type = 'logs-sort-order-change'; +} diff --git a/public/app/features/explore/Logs/Logs.test.tsx b/public/app/features/explore/Logs/Logs.test.tsx index 620f576e118..1749d92d48d 100644 --- a/public/app/features/explore/Logs/Logs.test.tsx +++ b/public/app/features/explore/Logs/Logs.test.tsx @@ -14,10 +14,12 @@ import { toUtc, createDataFrame, ExploreLogsPanelState, + DataQuery, } from '@grafana/data'; import { organizeFieldsTransformer } from '@grafana/data/src/transformations/transformers/organize'; import { config } from '@grafana/runtime'; import { extractFieldsTransformer } from 'app/features/transformers/extractFields/extractFields'; +import { LokiQueryDirection } from 'app/plugins/datasource/loki/dataquery.gen'; import { configureStore } from 'app/store/configureStore'; import { initialExploreState } from '../state/main'; @@ -46,6 +48,17 @@ jest.mock('../state/explorePane', () => ({ changePanelState: (exploreId: string, panel: 'logs', panelState: {} | ExploreLogsPanelState) => { return fakeChangePanelState(exploreId, panel, panelState); }, + changeQueries: (args: { queries: DataQuery[]; exploreId: string | undefined }) => { + return fakeChangeQueries(args); + }, +})); + +const fakeChangeQueries = jest.fn().mockReturnValue({ type: 'fakeChangeQueries' }); +jest.mock('../state/query', () => ({ + ...jest.requireActual('../state/query'), + changeQueries: (args: { queries: DataQuery[]; exploreId: string | undefined }) => { + return fakeChangeQueries(args); + }, })); describe('Logs', () => { @@ -377,6 +390,26 @@ describe('Logs', () => { expect(logRows[2].textContent).toContain('log message 3'); }); + it('should sync the query direction when changing the order of loki queries', async () => { + const query = { expr: '{a="b"}', refId: 'A', datasource: { type: 'loki' } }; + setup({ logsQueries: [query] }); + const oldestFirstSelection = screen.getByLabelText('Oldest first'); + await userEvent.click(oldestFirstSelection); + expect(fakeChangeQueries).toHaveBeenCalledWith({ + exploreId: 'left', + queries: [{ ...query, direction: LokiQueryDirection.Forward }], + }); + }); + + it('should not change the query direction when changing the order of non-loki queries', async () => { + fakeChangeQueries.mockClear(); + const query = { refId: 'B' }; + setup({ logsQueries: [query] }); + const oldestFirstSelection = screen.getByLabelText('Oldest first'); + await userEvent.click(oldestFirstSelection); + expect(fakeChangeQueries).not.toHaveBeenCalled(); + }); + describe('for permalinking', () => { it('should dispatch a `changePanelState` event without the id', () => { const panelState = { logs: { id: '1' } }; diff --git a/public/app/features/explore/Logs/Logs.tsx b/public/app/features/explore/Logs/Logs.tsx index 3a026431656..a82f30e196b 100644 --- a/public/app/features/explore/Logs/Logs.tsx +++ b/public/app/features/explore/Logs/Logs.tsx @@ -58,6 +58,7 @@ import { LogRowContextModal } from 'app/features/logs/components/log-context/Log import { LogLevelColor, dedupLogRows, filterLogLevels } from 'app/features/logs/logsModel'; import { getLogLevel, getLogLevelFromKey, getLogLevelInfo } from 'app/features/logs/utils'; import { LokiQueryDirection } from 'app/plugins/datasource/loki/dataquery.gen'; +import { isLokiQuery } from 'app/plugins/datasource/loki/queryUtils'; import { getState } from 'app/store/store'; import { ExploreItemState, useDispatch } from 'app/types'; @@ -72,6 +73,7 @@ import { import { useContentOutlineContext } from '../ContentOutline/ContentOutlineContext'; import { getUrlStateFromPaneState } from '../hooks/useStateSync'; import { changePanelState } from '../state/explorePane'; +import { changeQueries } from '../state/query'; import { LogsFeedback } from './LogsFeedback'; import { LogsMetaRow } from './LogsMetaRow'; @@ -468,6 +470,31 @@ const UnthemedLogs: React.FunctionComponent = (props: Props) => { const newSortOrder = logsSortOrder === LogsSortOrder.Descending ? LogsSortOrder.Ascending : LogsSortOrder.Descending; store.set(SETTINGS_KEYS.logsSortOrder, newSortOrder); + if (logsQueries) { + let hasLokiQueries = false; + const newQueries = logsQueries.map((query) => { + if (query.datasource?.type !== 'loki' || !isLokiQuery(query)) { + return query; + } + hasLokiQueries = true; + + if (query.direction === LokiQueryDirection.Scan) { + // Don't override Scan. When the direction is Scan it means that the user specifically assigned this direction to the query. + return query; + } + const newDirection = + newSortOrder === LogsSortOrder.Ascending ? LokiQueryDirection.Forward : LokiQueryDirection.Backward; + if (newDirection !== query.direction) { + query.direction = newDirection; + } + return query; + }); + + if (hasLokiQueries) { + dispatch(changeQueries({ exploreId, queries: newQueries })); + } + } + setLogsSortOrder(newSortOrder); }, 0); cancelFlippingTimer.current = window.setTimeout(() => setIsFlipping(false), 1000); diff --git a/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx b/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx index bb41f4cdf47..47626e222f7 100644 --- a/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx +++ b/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx @@ -15,6 +15,9 @@ import { LokiQueryEditorProps } from './types'; jest.mock('@grafana/runtime', () => { return { ...jest.requireActual('@grafana/runtime'), + getAppEvents: jest.fn().mockReturnValue({ + subscribe: jest.fn().mockReturnValue({ unsubscribe: jest.fn() }), + }), reportInteraction: jest.fn(), }; }); diff --git a/public/app/plugins/datasource/loki/components/LokiQueryEditorByApp.test.tsx b/public/app/plugins/datasource/loki/components/LokiQueryEditorByApp.test.tsx index c36399ea7dc..a7a55a5b709 100644 --- a/public/app/plugins/datasource/loki/components/LokiQueryEditorByApp.test.tsx +++ b/public/app/plugins/datasource/loki/components/LokiQueryEditorByApp.test.tsx @@ -9,6 +9,13 @@ import { testIds as regularTestIds } from './LokiQueryEditor'; import { LokiQueryEditorByApp } from './LokiQueryEditorByApp'; import { testIds as alertingTestIds } from './LokiQueryEditorForAlerting'; +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + getAppEvents: jest.fn().mockReturnValue({ + subscribe: jest.fn().mockReturnValue({ unsubscribe: jest.fn() }), + }), +})); + function setup(app: CoreApp): RenderResult { const dataSource = createLokiDatasource(); dataSource.metadataRequest = jest.fn(); diff --git a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoFieldWrapper.test.tsx b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoFieldWrapper.test.tsx index dadb297a1a4..ce1aabe2391 100644 --- a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoFieldWrapper.test.tsx +++ b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoFieldWrapper.test.tsx @@ -6,6 +6,13 @@ import { createLokiDatasource } from '../../__mocks__/datasource'; import { MonacoQueryFieldWrapper, Props } from './MonacoQueryFieldWrapper'; +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + getAppEvents: jest.fn().mockReturnValue({ + subscribe: jest.fn().mockReturnValue({ unsubscribe: jest.fn() }), + }), +})); + function renderComponent({ initialValue = '', onChange = jest.fn(), onRunQuery = jest.fn() }: Partial = {}) { const datasource = createLokiDatasource(); diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.test.tsx index cb827dd3bf5..bbd8f242906 100644 --- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.test.tsx +++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.test.tsx @@ -1,9 +1,37 @@ -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { LokiQuery, LokiQueryType } from '../../types'; +import { CoreApp, LogSortOrderChangeEvent, LogsSortOrder, store } from '@grafana/data'; +import { config, getAppEvents } from '@grafana/runtime'; -import { LokiQueryBuilderOptions } from './LokiQueryBuilderOptions'; +import { LokiQuery, LokiQueryDirection, LokiQueryType } from '../../types'; + +import { LokiQueryBuilderOptions, Props } from './LokiQueryBuilderOptions'; + +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + config: { + ...jest.requireActual('@grafana/runtime').config, + featureToggles: { + ...jest.requireActual('@grafana/runtime').featureToggles, + lokiShardSplitting: true, + }, + }, + getAppEvents: jest.fn(), +})); + +const subscribeMock = jest.fn(); +beforeAll(() => { + config.featureToggles.lokiShardSplitting = true; + subscribeMock.mockImplementation(() => ({ unsubscribe: jest.fn() })); + jest.mocked(getAppEvents).mockReturnValue({ + publish: jest.fn(), + getStream: jest.fn(), + subscribe: subscribeMock, + removeAllListeners: jest.fn(), + newScopedBus: jest.fn(), + }); +}); describe('LokiQueryBuilderOptions', () => { it('can change query type', async () => { @@ -86,7 +114,7 @@ describe('LokiQueryBuilderOptions', () => { }); it('shows correct options for log query', async () => { - setup({ expr: '{foo="bar"}' }); + setup({ expr: '{foo="bar"}', direction: LokiQueryDirection.Backward }); expect(screen.getByText('Line limit: 20')).toBeInTheDocument(); expect(screen.getByText('Type: Range')).toBeInTheDocument(); expect(screen.getByText('Direction: Backward')).toBeInTheDocument(); @@ -184,9 +212,91 @@ describe('LokiQueryBuilderOptions', () => { step: '4s', }); }); + + describe('Query direction', () => { + it("initializes query direction when it's empty", async () => { + const onChange = jest.fn(); + setup({ expr: '{foo="bar"}' }, onChange); + await waitFor(() => + expect(onChange).toHaveBeenCalledWith({ + expr: '{foo="bar"}', + refId: 'A', + direction: LokiQueryDirection.Backward, + }) + ); + }); + + it('uses backward as default in Explore with no previous stored preference', async () => { + const onChange = jest.fn(); + store.delete('grafana.explore.logs.sortOrder'); + setup({ expr: '{foo="bar"}' }, onChange, { app: CoreApp.Explore }); + await waitFor(() => + expect(onChange).toHaveBeenCalledWith({ + expr: '{foo="bar"}', + refId: 'A', + direction: LokiQueryDirection.Backward, + }) + ); + }); + + it('uses the stored sorting option to determine direction in Explore', async () => { + store.set('grafana.explore.logs.sortOrder', LogsSortOrder.Ascending); + const onChange = jest.fn(); + setup({ expr: '{foo="bar"}' }, onChange, { app: CoreApp.Explore }); + await waitFor(() => + expect(onChange).toHaveBeenCalledWith({ + expr: '{foo="bar"}', + refId: 'A', + direction: LokiQueryDirection.Forward, + }) + ); + store.delete('grafana.explore.logs.sortOrder'); + }); + + describe('Event handling', () => { + let listener: (event: LogSortOrderChangeEvent) => void = jest.fn(); + const onChangeMock = jest.fn(); + beforeEach(() => { + onChangeMock.mockClear(); + listener = jest.fn(); + subscribeMock.mockImplementation((_: unknown, callback: (event: LogSortOrderChangeEvent) => void) => { + listener = callback; + return { unsubscribe: jest.fn() }; + }); + }); + it('subscribes to sort change event and updates the direction', () => { + setup({ expr: '{foo="bar"}', direction: LokiQueryDirection.Backward }, onChangeMock, { + app: CoreApp.Dashboard, + }); + expect(screen.getByText(/Direction: Backward/)).toBeInTheDocument(); + listener( + new LogSortOrderChangeEvent({ + order: LogsSortOrder.Ascending, + }) + ); + expect(onChangeMock).toHaveBeenCalledTimes(1); + expect(onChangeMock).toHaveBeenCalledWith({ + direction: 'forward', + expr: '{foo="bar"}', + refId: 'A', + }); + }); + + it('does not change the direction when the current direction is scan', () => { + setup({ expr: '{foo="bar"}', direction: LokiQueryDirection.Scan }, onChangeMock, { app: CoreApp.Dashboard }); + expect(screen.getByText(/Direction: Scan/)).toBeInTheDocument(); + listener( + new LogSortOrderChangeEvent({ + order: LogsSortOrder.Ascending, + }) + ); + expect(onChangeMock).not.toHaveBeenCalled(); + }); + }); + }); }); -function setup(queryOverrides: Partial = {}, onChange = jest.fn()) { +function setup(queryOverrides: Partial = {}, onChange = jest.fn(), propOverrides: Partial = {}) { const props = { query: { refId: 'A', @@ -197,6 +307,7 @@ function setup(queryOverrides: Partial = {}, onChange = jest.fn()) { onChange, maxLines: 20, queryStats: { streams: 0, chunks: 0, bytes: 0, entries: 0 }, + ...propOverrides, }; const { container } = render(); diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx index bd7c2e6ff00..29d02331867 100644 --- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx +++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx @@ -1,10 +1,18 @@ import { trim } from 'lodash'; -import { useEffect, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import * as React from 'react'; -import { CoreApp, isValidDuration, isValidGrafanaDuration, SelectableValue } from '@grafana/data'; +import { + CoreApp, + isValidDuration, + isValidGrafanaDuration, + LogSortOrderChangeEvent, + LogsSortOrder, + SelectableValue, + store, +} from '@grafana/data'; import { EditorField, EditorRow, QueryOptionGroup } from '@grafana/experimental'; -import { config, reportInteraction } from '@grafana/runtime'; +import { config, getAppEvents, reportInteraction } from '@grafana/runtime'; import { Alert, AutoSizeInput, RadioButtonGroup, Select } from '@grafana/ui'; import { @@ -30,6 +38,13 @@ export const LokiQueryBuilderOptions = React.memo( ({ app, query, onChange, onRunQuery, maxLines, queryStats }) => { const [splitDurationValid, setSplitDurationValid] = useState(true); + useEffect(() => { + // Initialize the query direction according to the current environment. + if (!query.direction) { + onChange({ ...query, direction: getDefaultQueryDirection(app) }); + } + }, [app, onChange, query]); + useEffect(() => { if (query.step && !isValidGrafanaDuration(`${query.step}`) && parseInt(query.step, 10)) { onChange({ @@ -44,10 +59,13 @@ export const LokiQueryBuilderOptions = React.memo( onRunQuery(); }; - const onQueryDirectionChange = (value: LokiQueryDirection) => { - onChange({ ...query, direction: value }); - onRunQuery(); - }; + const onQueryDirectionChange = useCallback( + (value: LokiQueryDirection) => { + onChange({ ...query, direction: value }); + onRunQuery(); + }, + [onChange, onRunQuery, query] + ); const onResolutionChange = (option: SelectableValue) => { reportInteraction('grafana_loki_resolution_clicked', { @@ -87,14 +105,33 @@ export const LokiQueryBuilderOptions = React.memo( onRunQuery(); } + useEffect(() => { + if (app !== CoreApp.Dashboard && app !== CoreApp.PanelEditor) { + return; + } + const subscription = getAppEvents().subscribe(LogSortOrderChangeEvent, (sortEvent: LogSortOrderChangeEvent) => { + if (query.direction === LokiQueryDirection.Scan) { + return; + } + const newDirection = + sortEvent.payload.order === LogsSortOrder.Ascending + ? LokiQueryDirection.Forward + : LokiQueryDirection.Backward; + if (newDirection !== query.direction) { + onQueryDirectionChange(newDirection); + } + }); + return () => { + subscription.unsubscribe(); + }; + }, [app, onQueryDirectionChange, query.direction]); + let queryType = getLokiQueryType(query); const isLogQuery = isLogsQuery(query.expr); const filteredQueryTypeOptions = isLogQuery ? queryTypeOptions.filter((o) => o.value !== LokiQueryType.Instant) : queryTypeOptions; - const queryDirection = query.direction ?? LokiQueryDirection.Backward; - // if the state's queryType is still Instant, trigger a change to range for log queries if (isLogQuery && queryType === LokiQueryType.Instant) { onChange({ ...query, queryType: LokiQueryType.Range }); @@ -112,7 +149,7 @@ export const LokiQueryBuilderOptions = React.memo( ( /> - + )} @@ -214,7 +251,7 @@ function getCollapsedInfo( maxLines: number, isLogQuery: boolean, isValidStep: boolean, - direction: LokiQueryDirection + direction: LokiQueryDirection | undefined ): string[] { const queryTypeLabel = queryTypeOptions.find((x) => x.value === queryType); const resolutionLabel = RESOLUTION_OPTIONS.find((x) => x.value === (query.resolution ?? 1)); @@ -227,7 +264,7 @@ function getCollapsedInfo( items.push(`Type: ${queryTypeLabel?.label}`); - if (isLogQuery) { + if (isLogQuery && direction) { items.push(`Line limit: ${query.maxLines ?? maxLines}`); items.push(`Direction: ${getQueryDirectionLabel(direction)}`); } else { @@ -243,4 +280,20 @@ function getCollapsedInfo( return items; } +function getDefaultQueryDirection(app?: CoreApp) { + if (app !== CoreApp.Explore) { + /** + * The default direction is backward because the default sort order is Descending. + * See: + * - public/app/features/explore/Logs/Logs.tsx + * - public/app/plugins/panel/logs/module.tsx + */ + return LokiQueryDirection.Backward; + } + // See app/features/explore/Logs/utils/logs + const key = 'grafana.explore.logs.sortOrder'; + const storedOrder = store.get(key) || LogsSortOrder.Descending; + return storedOrder === LogsSortOrder.Ascending ? LokiQueryDirection.Forward : LokiQueryDirection.Backward; +} + LokiQueryBuilderOptions.displayName = 'LokiQueryBuilderOptions'; diff --git a/public/app/plugins/panel/logs/LogsPanel.test.tsx b/public/app/plugins/panel/logs/LogsPanel.test.tsx index 86795875d59..5f83f431ba3 100644 --- a/public/app/plugins/panel/logs/LogsPanel.test.tsx +++ b/public/app/plugins/panel/logs/LogsPanel.test.tsx @@ -13,7 +13,9 @@ import { LogsDedupStrategy, EventBusSrv, DataFrameType, + LogSortOrderChangeEvent, } from '@grafana/data'; +import { getAppEvents } from '@grafana/runtime'; import * as grafanaUI from '@grafana/ui'; import * as styles from 'app/features/logs/components/getLogRowStyles'; import { LogRowContextModal } from 'app/features/logs/components/log-context/LogRowContextModal'; @@ -39,6 +41,7 @@ const datasourceSrv = new DatasourceSrvMock(defaultDs, { const getDataSourceSrvMock = jest.fn().mockReturnValue(datasourceSrv); jest.mock('@grafana/runtime', () => ({ ...jest.requireActual('@grafana/runtime'), + getAppEvents: jest.fn(), getDataSourceSrv: () => getDataSourceSrvMock(), })); @@ -69,7 +72,35 @@ const defaultProps = { scopedVars: {}, startTime: 1, }, - series: [], + series: [ + createDataFrame({ + refId: 'A', + fields: [ + { + name: 'timestamp', + type: FieldType.time, + values: ['2019-04-26T09:28:11.352440161Z'], + }, + { + name: 'body', + type: FieldType.string, + values: ['logline text'], + }, + { + name: 'labels', + type: FieldType.other, + values: [ + { + app: 'common_app', + }, + ], + }, + ], + meta: { + type: DataFrameType.LogLines, + }, + }), + ], state: LoadingState.Done, timeRange: getDefaultTimeRange(), }, @@ -103,7 +134,32 @@ const defaultProps = { onChangeTimeRange: jest.fn(), }; +const publishMock = jest.fn(); +beforeAll(() => { + jest.mocked(getAppEvents).mockReturnValue({ + publish: publishMock, + getStream: jest.fn(), + subscribe: jest.fn(), + removeAllListeners: jest.fn(), + newScopedBus: jest.fn(), + }); +}); + describe('LogsPanel', () => { + it('publishes an event with the current sort order', async () => { + publishMock.mockClear(); + setup(); + + await screen.findByText('logline text'); + + expect(publishMock).toHaveBeenCalledTimes(1); + expect(publishMock).toHaveBeenCalledWith( + new LogSortOrderChangeEvent({ + order: LogsSortOrder.Descending, + }) + ); + }); + describe('when returned series include common labels', () => { const seriesWithCommonLabels = [ createDataFrame({ diff --git a/public/app/plugins/panel/logs/LogsPanel.tsx b/public/app/plugins/panel/logs/LogsPanel.tsx index 5b92496f86c..73d835edbbf 100644 --- a/public/app/plugins/panel/logs/LogsPanel.tsx +++ b/public/app/plugins/panel/logs/LogsPanel.tsx @@ -27,9 +27,10 @@ import { TimeZone, toUtc, urlUtil, + LogSortOrderChangeEvent, } from '@grafana/data'; import { convertRawToRange } from '@grafana/data/src/datetime/rangeutil'; -import { config } from '@grafana/runtime'; +import { config, getAppEvents } from '@grafana/runtime'; import { ScrollContainer, usePanelContext, useStyles2 } from '@grafana/ui'; import { getFieldLinksForExplore } from 'app/features/explore/utils/links'; import { InfiniteScroll } from 'app/features/logs/components/InfiniteScroll'; @@ -143,8 +144,16 @@ export const LogsPanel = ({ // Prevents the scroll position to change when new data from infinite scrolling is received const keepScrollPositionRef = useRef(false); let closeCallback = useRef<() => void>(); - const { eventBus, onAddAdHocFilter } = usePanelContext(); + + useEffect(() => { + getAppEvents().publish( + new LogSortOrderChangeEvent({ + order: sortOrder, + }) + ); + }, [sortOrder]); + const onLogRowHover = useCallback( (row?: LogRowModel) => { if (row) { From ed392594612675aebf048ed5e28a9ad2395475f7 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Fri, 10 Jan 2025 21:27:10 +0300 Subject: [PATCH 12/19] Search: Replace Origin calls with Repository (#98754) --- pkg/registry/apis/dashboard/legacy/client.go | 9 +- pkg/registry/apis/dashboard/legacy/storage.go | 9 +- pkg/storage/unified/resource/client.go | 26 +- pkg/storage/unified/resource/document.go | 9 +- pkg/storage/unified/resource/document_test.go | 2 +- pkg/storage/unified/resource/resource.pb.go | 1246 ++++++++++------- pkg/storage/unified/resource/resource.proto | 101 +- .../unified/resource/resource_grpc.pb.go | 173 ++- pkg/storage/unified/resource/search.go | 32 +- pkg/storage/unified/resource/server.go | 10 +- pkg/storage/unified/search/bleve.go | 105 +- pkg/storage/unified/search/bleve_mappings.go | 31 +- .../unified/search/bleve_mappings_test.go | 9 +- pkg/storage/unified/search/bleve_test.go | 78 +- .../search/testdata/doc/folder-aaa-out.json | 2 +- .../search/testdata/doc/folder-bbb-out.json | 2 +- .../search/testdata/doc/playlist-aaa-out.json | 2 +- .../search/testdata/doc/report-aaa-out.json | 2 +- pkg/storage/unified/sql/search.go | 15 +- 19 files changed, 1211 insertions(+), 652 deletions(-) diff --git a/pkg/registry/apis/dashboard/legacy/client.go b/pkg/registry/apis/dashboard/legacy/client.go index 4656fe49241..4c7fa63599d 100644 --- a/pkg/registry/apis/dashboard/legacy/client.go +++ b/pkg/registry/apis/dashboard/legacy/client.go @@ -57,9 +57,12 @@ func (d *directResourceClient) List(ctx context.Context, in *resource.ListReques return d.server.List(ctx, in) } -// Origin implements ResourceClient. -func (d *directResourceClient) Origin(ctx context.Context, in *resource.OriginRequest, opts ...grpc.CallOption) (*resource.OriginResponse, error) { - return d.server.Origin(ctx, in) +func (d *directResourceClient) ListRepositoryObjects(ctx context.Context, in *resource.ListRepositoryObjectsRequest, opts ...grpc.CallOption) (*resource.ListRepositoryObjectsResponse, error) { + return d.server.ListRepositoryObjects(ctx, in) +} + +func (d *directResourceClient) CountRepositoryObjects(ctx context.Context, in *resource.CountRepositoryObjectsRequest, opts ...grpc.CallOption) (*resource.CountRepositoryObjectsResponse, error) { + return d.server.CountRepositoryObjects(ctx, in) } // PutBlob implements ResourceClient. diff --git a/pkg/registry/apis/dashboard/legacy/storage.go b/pkg/registry/apis/dashboard/legacy/storage.go index e06a27ec43c..e44f7d16e02 100644 --- a/pkg/registry/apis/dashboard/legacy/storage.go +++ b/pkg/registry/apis/dashboard/legacy/storage.go @@ -330,9 +330,12 @@ func (a *dashboardSqlAccess) History(ctx context.Context, req *resource.HistoryR return list, err } -// Used for efficient provisioning -func (a *dashboardSqlAccess) Origin(context.Context, *resource.OriginRequest) (*resource.OriginResponse, error) { - return nil, fmt.Errorf("not yet (origin)") +func (a *dashboardSqlAccess) ListRepositoryObjects(ctx context.Context, req *resource.ListRepositoryObjectsRequest) (*resource.ListRepositoryObjectsResponse, error) { + return nil, fmt.Errorf("not implemented") +} + +func (a *dashboardSqlAccess) CountRepositoryObjects(context.Context, *resource.CountRepositoryObjectsRequest) (*resource.CountRepositoryObjectsResponse, error) { + return nil, fmt.Errorf("not implemented") } // GetStats implements ResourceServer. diff --git a/pkg/storage/unified/resource/client.go b/pkg/storage/unified/resource/client.go index dc0b8923e3e..f7c4e4c770b 100644 --- a/pkg/storage/unified/resource/client.go +++ b/pkg/storage/unified/resource/client.go @@ -8,11 +8,12 @@ import ( "github.com/fullstorydev/grpchan" "github.com/fullstorydev/grpchan/inprocgrpc" - authnlib "github.com/grafana/authlib/authn" - "github.com/grafana/authlib/claims" grpcAuth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth" "google.golang.org/grpc" + authnlib "github.com/grafana/authlib/authn" + "github.com/grafana/authlib/claims" + "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/services/authn/grpcutils" grpcUtils "github.com/grafana/grafana/pkg/storage/unified/resource/grpc" @@ -21,6 +22,7 @@ import ( type ResourceClient interface { ResourceStoreClient ResourceIndexClient + RepositoryIndexClient BlobStoreClient DiagnosticsClient } @@ -29,6 +31,7 @@ type ResourceClient interface { type resourceClient struct { ResourceStoreClient ResourceIndexClient + RepositoryIndexClient BlobStoreClient DiagnosticsClient } @@ -36,10 +39,11 @@ type resourceClient struct { func NewLegacyResourceClient(channel *grpc.ClientConn) ResourceClient { cc := grpchan.InterceptClientConn(channel, grpcUtils.UnaryClientInterceptor, grpcUtils.StreamClientInterceptor) return &resourceClient{ - ResourceStoreClient: NewResourceStoreClient(cc), - ResourceIndexClient: NewResourceIndexClient(cc), - BlobStoreClient: NewBlobStoreClient(cc), - DiagnosticsClient: NewDiagnosticsClient(cc), + ResourceStoreClient: NewResourceStoreClient(cc), + ResourceIndexClient: NewResourceIndexClient(cc), + RepositoryIndexClient: NewRepositoryIndexClient(cc), + BlobStoreClient: NewBlobStoreClient(cc), + DiagnosticsClient: NewDiagnosticsClient(cc), } } @@ -51,6 +55,7 @@ func NewLocalResourceClient(server ResourceServer) ResourceClient { for _, desc := range []*grpc.ServiceDesc{ &ResourceStore_ServiceDesc, &ResourceIndex_ServiceDesc, + &RepositoryIndex_ServiceDesc, &BlobStore_ServiceDesc, &Diagnostics_ServiceDesc, } { @@ -72,10 +77,11 @@ func NewLocalResourceClient(server ResourceServer) ResourceClient { cc := grpchan.InterceptClientConn(channel, clientInt.UnaryClientInterceptor, clientInt.StreamClientInterceptor) return &resourceClient{ - ResourceStoreClient: NewResourceStoreClient(cc), - ResourceIndexClient: NewResourceIndexClient(cc), - BlobStoreClient: NewBlobStoreClient(cc), - DiagnosticsClient: NewDiagnosticsClient(cc), + ResourceStoreClient: NewResourceStoreClient(cc), + ResourceIndexClient: NewResourceIndexClient(cc), + RepositoryIndexClient: NewRepositoryIndexClient(cc), + BlobStoreClient: NewBlobStoreClient(cc), + DiagnosticsClient: NewDiagnosticsClient(cc), } } diff --git a/pkg/storage/unified/resource/document.go b/pkg/storage/unified/resource/document.go index dbe12cc35b5..32116bb207d 100644 --- a/pkg/storage/unified/resource/document.go +++ b/pkg/storage/unified/resource/document.go @@ -102,7 +102,7 @@ type IndexableDocument struct { References ResourceReferences `json:"reference,omitempty"` // When the resource is managed by an upstream repository - RepoInfo *utils.ResourceRepositoryInfo `json:"repository,omitempty"` + RepoInfo *utils.ResourceRepositoryInfo `json:"repo,omitempty"` } func (m *IndexableDocument) Type() string { @@ -261,8 +261,11 @@ const SEARCH_FIELD_CREATED = "created" const SEARCH_FIELD_CREATED_BY = "createdBy" const SEARCH_FIELD_UPDATED = "updated" const SEARCH_FIELD_UPDATED_BY = "updatedBy" -const SEARCH_FIELD_REPOSITORY = "repository" -const SEARCH_FIELD_REPOSITORY_HASH = "repository_hash" + +const SEARCH_FIELD_REPOSITORY_NAME = "repo.name" +const SEARCH_FIELD_REPOSITORY_PATH = "repo.path" +const SEARCH_FIELD_REPOSITORY_HASH = "repo.hash" +const SEARCH_FIELD_REPOSITORY_TIME = "repo.time" const SEARCH_FIELD_SCORE = "_score" // the match score const SEARCH_FIELD_EXPLAIN = "_explain" // score explanation as JSON object diff --git a/pkg/storage/unified/resource/document_test.go b/pkg/storage/unified/resource/document_test.go index f382a01a0d1..44f180ce703 100644 --- a/pkg/storage/unified/resource/document_test.go +++ b/pkg/storage/unified/resource/document_test.go @@ -40,7 +40,7 @@ func TestStandardDocumentBuilder(t *testing.T) { "createdBy": "user:ABC", "updatedBy": "user:XYZ", "name": "test1", - "repository": { + "repo": { "name": "SQL", "path": "15", "hash": "xyz" diff --git a/pkg/storage/unified/resource/resource.pb.go b/pkg/storage/unified/resource/resource.pb.go index 341a43e4b04..5b363a766f2 100644 --- a/pkg/storage/unified/resource/resource.pb.go +++ b/pkg/storage/unified/resource/resource.pb.go @@ -173,7 +173,7 @@ func (x HealthCheckResponse_ServingStatus) Number() protoreflect.EnumNumber { // Deprecated: Use HealthCheckResponse_ServingStatus.Descriptor instead. func (HealthCheckResponse_ServingStatus) EnumDescriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{30, 0} + return file_resource_proto_rawDescGZIP(), []int{31, 0} } // See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more. @@ -248,7 +248,7 @@ func (x ResourceTableColumnDefinition_ColumnType) Number() protoreflect.EnumNumb // Deprecated: Use ResourceTableColumnDefinition_ColumnType.Descriptor instead. func (ResourceTableColumnDefinition_ColumnType) EnumDescriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{32, 0} + return file_resource_proto_rawDescGZIP(), []int{33, 0} } type PutBlobRequest_Method int32 @@ -296,7 +296,7 @@ func (x PutBlobRequest_Method) Number() protoreflect.EnumNumber { // Deprecated: Use PutBlobRequest_Method.Descriptor instead. func (PutBlobRequest_Method) EnumDescriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{36, 0} + return file_resource_proto_rawDescGZIP(), []int{37, 0} } type ResourceKey struct { @@ -2196,35 +2196,37 @@ func (x *HistoryResponse) GetError() *ErrorResult { return nil } -type OriginRequest struct { +// List items within a resource type & repository name +// Access control is managed above this request +type ListRepositoryObjectsRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // Starting from the requested page (other query parameters must match!) NextPageToken string `protobuf:"bytes,1,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` + // All results exist within this resource namespace+name + Key *ResourceKey `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + // The name of the repository + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` // Maximum number of items to return - Limit int64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` - // Resource identifier - Key *ResourceKey `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` - // List the deleted values (eg, show trash) - Origin string `protobuf:"bytes,4,opt,name=origin,proto3" json:"origin,omitempty"` + Limit int64 `protobuf:"varint,4,opt,name=limit,proto3" json:"limit,omitempty"` } -func (x *OriginRequest) Reset() { - *x = OriginRequest{} +func (x *ListRepositoryObjectsRequest) Reset() { + *x = ListRepositoryObjectsRequest{} mi := &file_resource_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *OriginRequest) String() string { +func (x *ListRepositoryObjectsRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*OriginRequest) ProtoMessage() {} +func (*ListRepositoryObjectsRequest) ProtoMessage() {} -func (x *OriginRequest) ProtoReflect() protoreflect.Message { +func (x *ListRepositoryObjectsRequest) ProtoReflect() protoreflect.Message { mi := &file_resource_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2236,74 +2238,66 @@ func (x *OriginRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use OriginRequest.ProtoReflect.Descriptor instead. -func (*OriginRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use ListRepositoryObjectsRequest.ProtoReflect.Descriptor instead. +func (*ListRepositoryObjectsRequest) Descriptor() ([]byte, []int) { return file_resource_proto_rawDescGZIP(), []int{26} } -func (x *OriginRequest) GetNextPageToken() string { +func (x *ListRepositoryObjectsRequest) GetNextPageToken() string { if x != nil { return x.NextPageToken } return "" } -func (x *OriginRequest) GetLimit() int64 { +func (x *ListRepositoryObjectsRequest) GetKey() *ResourceKey { + if x != nil { + return x.Key + } + return nil +} + +func (x *ListRepositoryObjectsRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ListRepositoryObjectsRequest) GetLimit() int64 { if x != nil { return x.Limit } return 0 } -func (x *OriginRequest) GetKey() *ResourceKey { - if x != nil { - return x.Key - } - return nil -} - -func (x *OriginRequest) GetOrigin() string { - if x != nil { - return x.Origin - } - return "" -} - -type ResourceOriginInfo struct { +type ListRepositoryObjectsResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The resource - Key *ResourceKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - // Size of the full resource body - ResourceSize int32 `protobuf:"varint,2,opt,name=resource_size,json=resourceSize,proto3" json:"resource_size,omitempty"` - // Hash for the resource - ResourceHash string `protobuf:"bytes,3,opt,name=resource_hash,json=resourceHash,proto3" json:"resource_hash,omitempty"` - // The origin name - Origin string `protobuf:"bytes,4,opt,name=origin,proto3" json:"origin,omitempty"` - // Path on the origin - Path string `protobuf:"bytes,5,opt,name=path,proto3" json:"path,omitempty"` - // Verification hash from the origin - Hash string `protobuf:"bytes,6,opt,name=hash,proto3" json:"hash,omitempty"` - // Change time from the origin - Timestamp int64 `protobuf:"varint,7,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // Item iterator + Items []*ListRepositoryObjectsResponse_Item `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` + // More results exist... pass this in the next request + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` + // Error details + Error *ErrorResult `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` } -func (x *ResourceOriginInfo) Reset() { - *x = ResourceOriginInfo{} +func (x *ListRepositoryObjectsResponse) Reset() { + *x = ListRepositoryObjectsResponse{} mi := &file_resource_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ResourceOriginInfo) String() string { +func (x *ListRepositoryObjectsResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ResourceOriginInfo) ProtoMessage() {} +func (*ListRepositoryObjectsResponse) ProtoMessage() {} -func (x *ResourceOriginInfo) ProtoReflect() protoreflect.Message { +func (x *ListRepositoryObjectsResponse) ProtoReflect() protoreflect.Message { mi := &file_resource_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2315,126 +2309,139 @@ func (x *ResourceOriginInfo) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ResourceOriginInfo.ProtoReflect.Descriptor instead. -func (*ResourceOriginInfo) Descriptor() ([]byte, []int) { +// Deprecated: Use ListRepositoryObjectsResponse.ProtoReflect.Descriptor instead. +func (*ListRepositoryObjectsResponse) Descriptor() ([]byte, []int) { return file_resource_proto_rawDescGZIP(), []int{27} } -func (x *ResourceOriginInfo) GetKey() *ResourceKey { - if x != nil { - return x.Key - } - return nil -} - -func (x *ResourceOriginInfo) GetResourceSize() int32 { - if x != nil { - return x.ResourceSize - } - return 0 -} - -func (x *ResourceOriginInfo) GetResourceHash() string { - if x != nil { - return x.ResourceHash - } - return "" -} - -func (x *ResourceOriginInfo) GetOrigin() string { - if x != nil { - return x.Origin - } - return "" -} - -func (x *ResourceOriginInfo) GetPath() string { - if x != nil { - return x.Path - } - return "" -} - -func (x *ResourceOriginInfo) GetHash() string { - if x != nil { - return x.Hash - } - return "" -} - -func (x *ResourceOriginInfo) GetTimestamp() int64 { - if x != nil { - return x.Timestamp - } - return 0 -} - -type OriginResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Items []*ResourceOriginInfo `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` - // More results exist... pass this in the next request - NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` - // ResourceVersion of the list response - ResourceVersion int64 `protobuf:"varint,3,opt,name=resource_version,json=resourceVersion,proto3" json:"resource_version,omitempty"` - // Error details - Error *ErrorResult `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *OriginResponse) Reset() { - *x = OriginResponse{} - mi := &file_resource_proto_msgTypes[28] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *OriginResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*OriginResponse) ProtoMessage() {} - -func (x *OriginResponse) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[28] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use OriginResponse.ProtoReflect.Descriptor instead. -func (*OriginResponse) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{28} -} - -func (x *OriginResponse) GetItems() []*ResourceOriginInfo { +func (x *ListRepositoryObjectsResponse) GetItems() []*ListRepositoryObjectsResponse_Item { if x != nil { return x.Items } return nil } -func (x *OriginResponse) GetNextPageToken() string { +func (x *ListRepositoryObjectsResponse) GetNextPageToken() string { if x != nil { return x.NextPageToken } return "" } -func (x *OriginResponse) GetResourceVersion() int64 { +func (x *ListRepositoryObjectsResponse) GetError() *ErrorResult { if x != nil { - return x.ResourceVersion + return x.Error } - return 0 + return nil } -func (x *OriginResponse) GetError() *ErrorResult { +// Count the items that exist with +type CountRepositoryObjectsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Namespace (tenant) + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + // The name of the repository + // (eventually empty to count across all repositories) + Repository string `protobuf:"bytes,2,opt,name=repository,proto3" json:"repository,omitempty"` +} + +func (x *CountRepositoryObjectsRequest) Reset() { + *x = CountRepositoryObjectsRequest{} + mi := &file_resource_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CountRepositoryObjectsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CountRepositoryObjectsRequest) ProtoMessage() {} + +func (x *CountRepositoryObjectsRequest) ProtoReflect() protoreflect.Message { + mi := &file_resource_proto_msgTypes[28] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CountRepositoryObjectsRequest.ProtoReflect.Descriptor instead. +func (*CountRepositoryObjectsRequest) Descriptor() ([]byte, []int) { + return file_resource_proto_rawDescGZIP(), []int{28} +} + +func (x *CountRepositoryObjectsRequest) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *CountRepositoryObjectsRequest) GetRepository() string { + if x != nil { + return x.Repository + } + return "" +} + +// Count the items that exist with +type CountRepositoryObjectsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Stats keyed by the repository name + Stats map[string]*CountRepositoryObjectsResponse_KindCount `protobuf:"bytes,1,rep,name=stats,proto3" json:"stats,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Error details + Error *ErrorResult `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *CountRepositoryObjectsResponse) Reset() { + *x = CountRepositoryObjectsResponse{} + mi := &file_resource_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CountRepositoryObjectsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CountRepositoryObjectsResponse) ProtoMessage() {} + +func (x *CountRepositoryObjectsResponse) ProtoReflect() protoreflect.Message { + mi := &file_resource_proto_msgTypes[29] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CountRepositoryObjectsResponse.ProtoReflect.Descriptor instead. +func (*CountRepositoryObjectsResponse) Descriptor() ([]byte, []int) { + return file_resource_proto_rawDescGZIP(), []int{29} +} + +func (x *CountRepositoryObjectsResponse) GetStats() map[string]*CountRepositoryObjectsResponse_KindCount { + if x != nil { + return x.Stats + } + return nil +} + +func (x *CountRepositoryObjectsResponse) GetError() *ErrorResult { if x != nil { return x.Error } @@ -2451,7 +2458,7 @@ type HealthCheckRequest struct { func (x *HealthCheckRequest) Reset() { *x = HealthCheckRequest{} - mi := &file_resource_proto_msgTypes[29] + mi := &file_resource_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2463,7 +2470,7 @@ func (x *HealthCheckRequest) String() string { func (*HealthCheckRequest) ProtoMessage() {} func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[29] + mi := &file_resource_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2476,7 +2483,7 @@ func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use HealthCheckRequest.ProtoReflect.Descriptor instead. func (*HealthCheckRequest) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{29} + return file_resource_proto_rawDescGZIP(), []int{30} } func (x *HealthCheckRequest) GetService() string { @@ -2496,7 +2503,7 @@ type HealthCheckResponse struct { func (x *HealthCheckResponse) Reset() { *x = HealthCheckResponse{} - mi := &file_resource_proto_msgTypes[30] + mi := &file_resource_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2508,7 +2515,7 @@ func (x *HealthCheckResponse) String() string { func (*HealthCheckResponse) ProtoMessage() {} func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[30] + mi := &file_resource_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2521,7 +2528,7 @@ func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use HealthCheckResponse.ProtoReflect.Descriptor instead. func (*HealthCheckResponse) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{30} + return file_resource_proto_rawDescGZIP(), []int{31} } func (x *HealthCheckResponse) GetStatus() HealthCheckResponse_ServingStatus { @@ -2563,7 +2570,7 @@ type ResourceTable struct { func (x *ResourceTable) Reset() { *x = ResourceTable{} - mi := &file_resource_proto_msgTypes[31] + mi := &file_resource_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2575,7 +2582,7 @@ func (x *ResourceTable) String() string { func (*ResourceTable) ProtoMessage() {} func (x *ResourceTable) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[31] + mi := &file_resource_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2588,7 +2595,7 @@ func (x *ResourceTable) ProtoReflect() protoreflect.Message { // Deprecated: Use ResourceTable.ProtoReflect.Descriptor instead. func (*ResourceTable) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{31} + return file_resource_proto_rawDescGZIP(), []int{32} } func (x *ResourceTable) GetColumns() []*ResourceTableColumnDefinition { @@ -2636,7 +2643,7 @@ type ResourceTableColumnDefinition struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // Defines the column type. In k8s, this will resolve into both the type and format fields Type ResourceTableColumnDefinition_ColumnType `protobuf:"varint,2,opt,name=type,proto3,enum=resource.ResourceTableColumnDefinition_ColumnType" json:"type,omitempty"` - // The value is an arry of given type + // The value is an array of given type IsArray bool `protobuf:"varint,3,opt,name=is_array,json=isArray,proto3" json:"is_array,omitempty"` // description is a human readable description of this column. Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` @@ -2650,7 +2657,7 @@ type ResourceTableColumnDefinition struct { func (x *ResourceTableColumnDefinition) Reset() { *x = ResourceTableColumnDefinition{} - mi := &file_resource_proto_msgTypes[32] + mi := &file_resource_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2662,7 +2669,7 @@ func (x *ResourceTableColumnDefinition) String() string { func (*ResourceTableColumnDefinition) ProtoMessage() {} func (x *ResourceTableColumnDefinition) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[32] + mi := &file_resource_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2675,7 +2682,7 @@ func (x *ResourceTableColumnDefinition) ProtoReflect() protoreflect.Message { // Deprecated: Use ResourceTableColumnDefinition.ProtoReflect.Descriptor instead. func (*ResourceTableColumnDefinition) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{32} + return file_resource_proto_rawDescGZIP(), []int{33} } func (x *ResourceTableColumnDefinition) GetName() string { @@ -2744,7 +2751,7 @@ type ResourceTableRow struct { func (x *ResourceTableRow) Reset() { *x = ResourceTableRow{} - mi := &file_resource_proto_msgTypes[33] + mi := &file_resource_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2756,7 +2763,7 @@ func (x *ResourceTableRow) String() string { func (*ResourceTableRow) ProtoMessage() {} func (x *ResourceTableRow) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[33] + mi := &file_resource_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2769,7 +2776,7 @@ func (x *ResourceTableRow) ProtoReflect() protoreflect.Message { // Deprecated: Use ResourceTableRow.ProtoReflect.Descriptor instead. func (*ResourceTableRow) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{33} + return file_resource_proto_rawDescGZIP(), []int{34} } func (x *ResourceTableRow) GetKey() *ResourceKey { @@ -2813,7 +2820,7 @@ type RestoreRequest struct { func (x *RestoreRequest) Reset() { *x = RestoreRequest{} - mi := &file_resource_proto_msgTypes[34] + mi := &file_resource_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2825,7 +2832,7 @@ func (x *RestoreRequest) String() string { func (*RestoreRequest) ProtoMessage() {} func (x *RestoreRequest) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[34] + mi := &file_resource_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2838,7 +2845,7 @@ func (x *RestoreRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RestoreRequest.ProtoReflect.Descriptor instead. func (*RestoreRequest) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{34} + return file_resource_proto_rawDescGZIP(), []int{35} } func (x *RestoreRequest) GetKey() *ResourceKey { @@ -2868,7 +2875,7 @@ type RestoreResponse struct { func (x *RestoreResponse) Reset() { *x = RestoreResponse{} - mi := &file_resource_proto_msgTypes[35] + mi := &file_resource_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2880,7 +2887,7 @@ func (x *RestoreResponse) String() string { func (*RestoreResponse) ProtoMessage() {} func (x *RestoreResponse) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[35] + mi := &file_resource_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2893,7 +2900,7 @@ func (x *RestoreResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RestoreResponse.ProtoReflect.Descriptor instead. func (*RestoreResponse) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{35} + return file_resource_proto_rawDescGZIP(), []int{36} } func (x *RestoreResponse) GetError() *ErrorResult { @@ -2929,7 +2936,7 @@ type PutBlobRequest struct { func (x *PutBlobRequest) Reset() { *x = PutBlobRequest{} - mi := &file_resource_proto_msgTypes[36] + mi := &file_resource_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2941,7 +2948,7 @@ func (x *PutBlobRequest) String() string { func (*PutBlobRequest) ProtoMessage() {} func (x *PutBlobRequest) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[36] + mi := &file_resource_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2954,7 +2961,7 @@ func (x *PutBlobRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PutBlobRequest.ProtoReflect.Descriptor instead. func (*PutBlobRequest) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{36} + return file_resource_proto_rawDescGZIP(), []int{37} } func (x *PutBlobRequest) GetResource() *ResourceKey { @@ -3008,7 +3015,7 @@ type PutBlobResponse struct { func (x *PutBlobResponse) Reset() { *x = PutBlobResponse{} - mi := &file_resource_proto_msgTypes[37] + mi := &file_resource_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3020,7 +3027,7 @@ func (x *PutBlobResponse) String() string { func (*PutBlobResponse) ProtoMessage() {} func (x *PutBlobResponse) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[37] + mi := &file_resource_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3033,7 +3040,7 @@ func (x *PutBlobResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PutBlobResponse.ProtoReflect.Descriptor instead. func (*PutBlobResponse) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{37} + return file_resource_proto_rawDescGZIP(), []int{38} } func (x *PutBlobResponse) GetError() *ErrorResult { @@ -3099,7 +3106,7 @@ type GetBlobRequest struct { func (x *GetBlobRequest) Reset() { *x = GetBlobRequest{} - mi := &file_resource_proto_msgTypes[38] + mi := &file_resource_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3111,7 +3118,7 @@ func (x *GetBlobRequest) String() string { func (*GetBlobRequest) ProtoMessage() {} func (x *GetBlobRequest) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[38] + mi := &file_resource_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3124,7 +3131,7 @@ func (x *GetBlobRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlobRequest.ProtoReflect.Descriptor instead. func (*GetBlobRequest) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{38} + return file_resource_proto_rawDescGZIP(), []int{39} } func (x *GetBlobRequest) GetResource() *ResourceKey { @@ -3167,7 +3174,7 @@ type GetBlobResponse struct { func (x *GetBlobResponse) Reset() { *x = GetBlobResponse{} - mi := &file_resource_proto_msgTypes[39] + mi := &file_resource_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3179,7 +3186,7 @@ func (x *GetBlobResponse) String() string { func (*GetBlobResponse) ProtoMessage() {} func (x *GetBlobResponse) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[39] + mi := &file_resource_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3192,7 +3199,7 @@ func (x *GetBlobResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlobResponse.ProtoReflect.Descriptor instead. func (*GetBlobResponse) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{39} + return file_resource_proto_rawDescGZIP(), []int{40} } func (x *GetBlobResponse) GetError() *ErrorResult { @@ -3234,7 +3241,7 @@ type WatchEvent_Resource struct { func (x *WatchEvent_Resource) Reset() { *x = WatchEvent_Resource{} - mi := &file_resource_proto_msgTypes[40] + mi := &file_resource_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3246,7 +3253,7 @@ func (x *WatchEvent_Resource) String() string { func (*WatchEvent_Resource) ProtoMessage() {} func (x *WatchEvent_Resource) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[40] + mi := &file_resource_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3291,7 +3298,7 @@ type ResourceStatsResponse_Stats struct { func (x *ResourceStatsResponse_Stats) Reset() { *x = ResourceStatsResponse_Stats{} - mi := &file_resource_proto_msgTypes[41] + mi := &file_resource_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3303,7 +3310,7 @@ func (x *ResourceStatsResponse_Stats) String() string { func (*ResourceStatsResponse_Stats) ProtoMessage() {} func (x *ResourceStatsResponse_Stats) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[41] + mi := &file_resource_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3351,7 +3358,7 @@ type ResourceSearchRequest_Sort struct { func (x *ResourceSearchRequest_Sort) Reset() { *x = ResourceSearchRequest_Sort{} - mi := &file_resource_proto_msgTypes[42] + mi := &file_resource_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3363,7 +3370,7 @@ func (x *ResourceSearchRequest_Sort) String() string { func (*ResourceSearchRequest_Sort) ProtoMessage() {} func (x *ResourceSearchRequest_Sort) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[42] + mi := &file_resource_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3404,7 +3411,7 @@ type ResourceSearchRequest_Facet struct { func (x *ResourceSearchRequest_Facet) Reset() { *x = ResourceSearchRequest_Facet{} - mi := &file_resource_proto_msgTypes[43] + mi := &file_resource_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3416,7 +3423,7 @@ func (x *ResourceSearchRequest_Facet) String() string { func (*ResourceSearchRequest_Facet) ProtoMessage() {} func (x *ResourceSearchRequest_Facet) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[43] + mi := &file_resource_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3462,7 +3469,7 @@ type ResourceSearchResponse_Facet struct { func (x *ResourceSearchResponse_Facet) Reset() { *x = ResourceSearchResponse_Facet{} - mi := &file_resource_proto_msgTypes[45] + mi := &file_resource_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3474,7 +3481,7 @@ func (x *ResourceSearchResponse_Facet) String() string { func (*ResourceSearchResponse_Facet) ProtoMessage() {} func (x *ResourceSearchResponse_Facet) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[45] + mi := &file_resource_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3529,7 +3536,7 @@ type ResourceSearchResponse_TermFacet struct { func (x *ResourceSearchResponse_TermFacet) Reset() { *x = ResourceSearchResponse_TermFacet{} - mi := &file_resource_proto_msgTypes[46] + mi := &file_resource_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3541,7 +3548,7 @@ func (x *ResourceSearchResponse_TermFacet) String() string { func (*ResourceSearchResponse_TermFacet) ProtoMessage() {} func (x *ResourceSearchResponse_TermFacet) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[46] + mi := &file_resource_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3571,6 +3578,158 @@ func (x *ResourceSearchResponse_TermFacet) GetCount() int64 { return 0 } +type ListRepositoryObjectsResponse_Item struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The resource object key + Object *ResourceKey `protobuf:"bytes,1,opt,name=object,proto3" json:"object,omitempty"` + // Hash for the resource + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` + // Verification hash from the origin + Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"` + // Change time from the origin + Time int64 `protobuf:"varint,5,opt,name=time,proto3" json:"time,omitempty"` + // Title inside the payload + Title string `protobuf:"bytes,6,opt,name=title,proto3" json:"title,omitempty"` + // The name of the folder in metadata + Folder string `protobuf:"bytes,7,opt,name=folder,proto3" json:"folder,omitempty"` +} + +func (x *ListRepositoryObjectsResponse_Item) Reset() { + *x = ListRepositoryObjectsResponse_Item{} + mi := &file_resource_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListRepositoryObjectsResponse_Item) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListRepositoryObjectsResponse_Item) ProtoMessage() {} + +func (x *ListRepositoryObjectsResponse_Item) ProtoReflect() protoreflect.Message { + mi := &file_resource_proto_msgTypes[49] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListRepositoryObjectsResponse_Item.ProtoReflect.Descriptor instead. +func (*ListRepositoryObjectsResponse_Item) Descriptor() ([]byte, []int) { + return file_resource_proto_rawDescGZIP(), []int{27, 0} +} + +func (x *ListRepositoryObjectsResponse_Item) GetObject() *ResourceKey { + if x != nil { + return x.Object + } + return nil +} + +func (x *ListRepositoryObjectsResponse_Item) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *ListRepositoryObjectsResponse_Item) GetHash() string { + if x != nil { + return x.Hash + } + return "" +} + +func (x *ListRepositoryObjectsResponse_Item) GetTime() int64 { + if x != nil { + return x.Time + } + return 0 +} + +func (x *ListRepositoryObjectsResponse_Item) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *ListRepositoryObjectsResponse_Item) GetFolder() string { + if x != nil { + return x.Folder + } + return "" +} + +type CountRepositoryObjectsResponse_KindCount struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Group string `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` + Resource string `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"` + Count int64 `protobuf:"varint,3,opt,name=count,proto3" json:"count,omitempty"` +} + +func (x *CountRepositoryObjectsResponse_KindCount) Reset() { + *x = CountRepositoryObjectsResponse_KindCount{} + mi := &file_resource_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CountRepositoryObjectsResponse_KindCount) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CountRepositoryObjectsResponse_KindCount) ProtoMessage() {} + +func (x *CountRepositoryObjectsResponse_KindCount) ProtoReflect() protoreflect.Message { + mi := &file_resource_proto_msgTypes[50] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CountRepositoryObjectsResponse_KindCount.ProtoReflect.Descriptor instead. +func (*CountRepositoryObjectsResponse_KindCount) Descriptor() ([]byte, []int) { + return file_resource_proto_rawDescGZIP(), []int{29, 0} +} + +func (x *CountRepositoryObjectsResponse_KindCount) GetGroup() string { + if x != nil { + return x.Group + } + return "" +} + +func (x *CountRepositoryObjectsResponse_KindCount) GetResource() string { + if x != nil { + return x.Resource + } + return "" +} + +func (x *CountRepositoryObjectsResponse_KindCount) GetCount() int64 { + if x != nil { + return x.Count + } + return 0 +} + // These values are not part of standard k8s format // however these are useful when indexing and analyzing results type ResourceTableColumnDefinition_Properties struct { @@ -3594,7 +3753,7 @@ type ResourceTableColumnDefinition_Properties struct { func (x *ResourceTableColumnDefinition_Properties) Reset() { *x = ResourceTableColumnDefinition_Properties{} - mi := &file_resource_proto_msgTypes[48] + mi := &file_resource_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3606,7 +3765,7 @@ func (x *ResourceTableColumnDefinition_Properties) String() string { func (*ResourceTableColumnDefinition_Properties) ProtoMessage() {} func (x *ResourceTableColumnDefinition_Properties) ProtoReflect() protoreflect.Message { - mi := &file_resource_proto_msgTypes[48] + mi := &file_resource_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3619,7 +3778,7 @@ func (x *ResourceTableColumnDefinition_Properties) ProtoReflect() protoreflect.M // Deprecated: Use ResourceTableColumnDefinition_Properties.ProtoReflect.Descriptor instead. func (*ResourceTableColumnDefinition_Properties) Descriptor() ([]byte, []int) { - return file_resource_proto_rawDescGZIP(), []int{32, 0} + return file_resource_proto_rawDescGZIP(), []int{33, 0} } func (x *ResourceTableColumnDefinition_Properties) GetUniqueValues() bool { @@ -3960,247 +4119,281 @@ var file_resource_proto_rawDesc = []byte{ 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x8e, 0x01, 0x0a, 0x0d, - 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, + 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x99, 0x01, 0x0a, 0x1c, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, + 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0xda, 0x02, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x05, 0x69, 0x74, 0x65, + 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, + 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x27, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x22, 0xe5, 0x01, 0x0a, - 0x12, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x69, 0x7a, - 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x48, 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x12, 0x12, - 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, - 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x22, 0xc4, 0x01, 0x0a, 0x0e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, - 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2b, - 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x2e, 0x0a, 0x12, 0x48, - 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0xab, 0x01, 0x0a, 0x13, - 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, - 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x4f, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, - 0x47, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4e, 0x4f, 0x54, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, - 0x4e, 0x47, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x5f, - 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x22, 0x87, 0x02, 0x0a, 0x0d, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x07, 0x63, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x2e, - 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x12, 0x26, - 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, - 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x69, - 0x74, 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x12, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x49, 0x74, 0x65, 0x6d, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x22, 0xf1, 0x04, 0x0a, 0x1d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, - 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, 0x12, 0x20, 0x0a, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x52, - 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x1a, 0x9f, 0x01, 0x0a, 0x04, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x2d, 0x0a, 0x06, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, + 0x65, 0x79, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, + 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, + 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, + 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, + 0x6c, 0x64, 0x65, 0x72, 0x22, 0x5d, 0x0a, 0x1d, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x6f, 0x72, 0x79, 0x22, 0xdb, 0x02, 0x0a, 0x1e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, + 0x73, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x1a, 0x53, + 0x0a, 0x09, 0x4b, 0x69, 0x6e, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x1a, 0x6c, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x48, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4b, 0x69, 0x6e, + 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x2e, 0x0a, 0x12, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x22, 0xab, 0x01, 0x0a, 0x13, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x4f, + 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, + 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4e, 0x4f, 0x54, + 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x45, + 0x52, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x22, + 0x87, 0x02, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, + 0x65, 0x12, 0x41, 0x0a, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x70, - 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, - 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x1a, 0xae, - 0x01, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x23, 0x0a, - 0x0d, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x66, 0x72, 0x65, 0x65, 0x54, 0x65, 0x78, 0x74, 0x12, - 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x12, - 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x74, 0x5f, 0x6e, 0x75, 0x6c, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x07, 0x6e, 0x6f, 0x74, 0x4e, 0x75, 0x6c, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, - 0x95, 0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, - 0x0a, 0x0c, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, - 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, - 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, - 0x33, 0x32, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, 0x04, 0x12, - 0x09, 0x0a, 0x05, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x4f, - 0x55, 0x42, 0x4c, 0x45, 0x10, 0x06, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x41, 0x54, 0x45, 0x10, 0x07, - 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x10, 0x08, 0x12, - 0x0a, 0x0a, 0x06, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x4f, - 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x0a, 0x22, 0x94, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x12, 0x27, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x14, 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, - 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x64, - 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x63, 0x6f, 0x6c, + 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x52, 0x04, + 0x72, 0x6f, 0x77, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, + 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x29, 0x0a, 0x10, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x65, 0x6d, 0x61, 0x69, + 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, + 0x49, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xf1, 0x04, 0x0a, 0x1d, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, + 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x46, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x69, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, - 0xd3, 0x01, 0x0a, 0x0e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, + 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x41, 0x72, 0x72, + 0x61, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x52, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, + 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x52, 0x0a, 0x70, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x1a, 0xae, 0x01, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, + 0x69, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x71, + 0x75, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x65, + 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x66, 0x72, 0x65, + 0x65, 0x54, 0x65, 0x78, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x61, + 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x74, 0x5f, 0x6e, 0x75, 0x6c, + 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6e, 0x6f, 0x74, 0x4e, 0x75, 0x6c, 0x6c, + 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x95, 0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, + 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x10, 0x02, 0x12, + 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, + 0x54, 0x36, 0x34, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x10, 0x05, + 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x4f, 0x55, 0x42, 0x4c, 0x45, 0x10, 0x06, 0x12, 0x08, 0x0a, 0x04, + 0x44, 0x41, 0x54, 0x45, 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x54, + 0x49, 0x4d, 0x45, 0x10, 0x08, 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, + 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x0a, 0x22, 0x94, 0x01, + 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, + 0x6f, 0x77, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x12, 0x16, 0x0a, 0x06, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x22, 0x64, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x69, 0x0a, 0x0f, 0x52, 0x65, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xd3, 0x01, 0x0a, 0x0e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, + 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, + 0x79, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x6d, + 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x06, 0x6d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1c, 0x0a, + 0x06, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x08, 0x0a, 0x04, 0x47, 0x52, 0x50, 0x43, 0x10, + 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x01, 0x22, 0xc1, 0x01, 0x0a, 0x0f, + 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, + 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x10, + 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, + 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, + 0x73, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6d, 0x65, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x69, 0x6d, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x22, + 0x98, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x08, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, - 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x21, - 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1c, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x12, 0x08, 0x0a, 0x04, 0x47, 0x52, 0x50, 0x43, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, - 0x54, 0x54, 0x50, 0x10, 0x01, 0x22, 0xc1, 0x01, 0x0a, 0x0f, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, - 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, - 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, - 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, - 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x22, 0x98, 0x01, 0x0a, 0x0e, 0x47, 0x65, - 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, - 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x75, - 0x73, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6d, 0x75, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x42, - 0x79, 0x74, 0x65, 0x73, 0x22, 0x89, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x2a, 0x33, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x4f, - 0x6c, 0x64, 0x65, 0x72, 0x54, 0x68, 0x61, 0x6e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x78, - 0x61, 0x63, 0x74, 0x10, 0x01, 0x32, 0xad, 0x03, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, - 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, - 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x12, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x74, - 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x15, 0x2e, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x05, - 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x16, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x30, 0x01, 0x32, 0xa6, 0x02, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x4b, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x12, 0x1f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, - 0x12, 0x1e, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x18, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x12, 0x17, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6d, 0x75, 0x73, 0x74, + 0x50, 0x72, 0x6f, 0x78, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x89, 0x01, 0x0a, 0x0f, 0x47, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, + 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x75, + 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x21, 0x0a, + 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x33, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x10, + 0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x4f, 0x6c, 0x64, 0x65, 0x72, 0x54, 0x68, 0x61, 0x6e, 0x10, 0x00, + 0x12, 0x09, 0x0a, 0x05, 0x45, 0x78, 0x61, 0x63, 0x74, 0x10, 0x01, 0x32, 0xad, 0x03, 0x0a, 0x0d, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x35, 0x0a, + 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x17, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x8b, - 0x01, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x3e, 0x0a, 0x07, - 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x2e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x50, 0x75, 0x74, - 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x07, - 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x57, 0x0a, 0x0b, - 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x48, 0x0a, 0x09, 0x49, - 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x12, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x39, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x67, 0x72, 0x61, 0x66, - 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f, - 0x75, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, + 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x52, + 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x4c, + 0x69, 0x73, 0x74, 0x12, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x37, 0x0a, 0x05, 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x16, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, + 0x61, 0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x32, 0xe9, 0x01, 0x0a, 0x0d, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x4b, 0x0a, + 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x47, 0x65, + 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x1e, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x48, 0x69, 0x73, 0x74, 0x6f, + 0x72, 0x79, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x69, + 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xe8, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x6b, 0x0a, 0x16, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x12, 0x26, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x6f, 0x72, 0x79, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x32, 0x8b, 0x01, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x6f, 0x72, 0x65, + 0x12, 0x3e, 0x0a, 0x07, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x18, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x50, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x3e, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x18, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x32, 0x57, 0x0a, 0x0b, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, + 0x48, 0x0a, 0x09, 0x49, 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x12, 0x1c, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x39, 0x5a, 0x37, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, + 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x2f, 0x75, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2f, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -4216,7 +4409,7 @@ func file_resource_proto_rawDescGZIP() []byte { } var file_resource_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_resource_proto_msgTypes = make([]protoimpl.MessageInfo, 49) +var file_resource_proto_msgTypes = make([]protoimpl.MessageInfo, 53) var file_resource_proto_goTypes = []any{ (ResourceVersionMatch)(0), // 0: resource.ResourceVersionMatch (WatchEvent_Type)(0), // 1: resource.WatchEvent.Type @@ -4249,29 +4442,33 @@ var file_resource_proto_goTypes = []any{ (*ResourceSearchResponse)(nil), // 28: resource.ResourceSearchResponse (*HistoryRequest)(nil), // 29: resource.HistoryRequest (*HistoryResponse)(nil), // 30: resource.HistoryResponse - (*OriginRequest)(nil), // 31: resource.OriginRequest - (*ResourceOriginInfo)(nil), // 32: resource.ResourceOriginInfo - (*OriginResponse)(nil), // 33: resource.OriginResponse - (*HealthCheckRequest)(nil), // 34: resource.HealthCheckRequest - (*HealthCheckResponse)(nil), // 35: resource.HealthCheckResponse - (*ResourceTable)(nil), // 36: resource.ResourceTable - (*ResourceTableColumnDefinition)(nil), // 37: resource.ResourceTableColumnDefinition - (*ResourceTableRow)(nil), // 38: resource.ResourceTableRow - (*RestoreRequest)(nil), // 39: resource.RestoreRequest - (*RestoreResponse)(nil), // 40: resource.RestoreResponse - (*PutBlobRequest)(nil), // 41: resource.PutBlobRequest - (*PutBlobResponse)(nil), // 42: resource.PutBlobResponse - (*GetBlobRequest)(nil), // 43: resource.GetBlobRequest - (*GetBlobResponse)(nil), // 44: resource.GetBlobResponse - (*WatchEvent_Resource)(nil), // 45: resource.WatchEvent.Resource - (*ResourceStatsResponse_Stats)(nil), // 46: resource.ResourceStatsResponse.Stats - (*ResourceSearchRequest_Sort)(nil), // 47: resource.ResourceSearchRequest.Sort - (*ResourceSearchRequest_Facet)(nil), // 48: resource.ResourceSearchRequest.Facet - nil, // 49: resource.ResourceSearchRequest.FacetEntry - (*ResourceSearchResponse_Facet)(nil), // 50: resource.ResourceSearchResponse.Facet - (*ResourceSearchResponse_TermFacet)(nil), // 51: resource.ResourceSearchResponse.TermFacet - nil, // 52: resource.ResourceSearchResponse.FacetEntry - (*ResourceTableColumnDefinition_Properties)(nil), // 53: resource.ResourceTableColumnDefinition.Properties + (*ListRepositoryObjectsRequest)(nil), // 31: resource.ListRepositoryObjectsRequest + (*ListRepositoryObjectsResponse)(nil), // 32: resource.ListRepositoryObjectsResponse + (*CountRepositoryObjectsRequest)(nil), // 33: resource.CountRepositoryObjectsRequest + (*CountRepositoryObjectsResponse)(nil), // 34: resource.CountRepositoryObjectsResponse + (*HealthCheckRequest)(nil), // 35: resource.HealthCheckRequest + (*HealthCheckResponse)(nil), // 36: resource.HealthCheckResponse + (*ResourceTable)(nil), // 37: resource.ResourceTable + (*ResourceTableColumnDefinition)(nil), // 38: resource.ResourceTableColumnDefinition + (*ResourceTableRow)(nil), // 39: resource.ResourceTableRow + (*RestoreRequest)(nil), // 40: resource.RestoreRequest + (*RestoreResponse)(nil), // 41: resource.RestoreResponse + (*PutBlobRequest)(nil), // 42: resource.PutBlobRequest + (*PutBlobResponse)(nil), // 43: resource.PutBlobResponse + (*GetBlobRequest)(nil), // 44: resource.GetBlobRequest + (*GetBlobResponse)(nil), // 45: resource.GetBlobResponse + (*WatchEvent_Resource)(nil), // 46: resource.WatchEvent.Resource + (*ResourceStatsResponse_Stats)(nil), // 47: resource.ResourceStatsResponse.Stats + (*ResourceSearchRequest_Sort)(nil), // 48: resource.ResourceSearchRequest.Sort + (*ResourceSearchRequest_Facet)(nil), // 49: resource.ResourceSearchRequest.Facet + nil, // 50: resource.ResourceSearchRequest.FacetEntry + (*ResourceSearchResponse_Facet)(nil), // 51: resource.ResourceSearchResponse.Facet + (*ResourceSearchResponse_TermFacet)(nil), // 52: resource.ResourceSearchResponse.TermFacet + nil, // 53: resource.ResourceSearchResponse.FacetEntry + (*ListRepositoryObjectsResponse_Item)(nil), // 54: resource.ListRepositoryObjectsResponse.Item + (*CountRepositoryObjectsResponse_KindCount)(nil), // 55: resource.CountRepositoryObjectsResponse.KindCount + nil, // 56: resource.CountRepositoryObjectsResponse.StatsEntry + (*ResourceTableColumnDefinition_Properties)(nil), // 57: resource.ResourceTableColumnDefinition.Properties } var file_resource_proto_depIdxs = []int32{ 9, // 0: resource.ErrorResult.details:type_name -> resource.ErrorDetails @@ -4293,74 +4490,79 @@ var file_resource_proto_depIdxs = []int32{ 8, // 16: resource.ListResponse.error:type_name -> resource.ErrorResult 20, // 17: resource.WatchRequest.options:type_name -> resource.ListOptions 1, // 18: resource.WatchEvent.type:type_name -> resource.WatchEvent.Type - 45, // 19: resource.WatchEvent.resource:type_name -> resource.WatchEvent.Resource - 45, // 20: resource.WatchEvent.previous:type_name -> resource.WatchEvent.Resource + 46, // 19: resource.WatchEvent.resource:type_name -> resource.WatchEvent.Resource + 46, // 20: resource.WatchEvent.previous:type_name -> resource.WatchEvent.Resource 8, // 21: resource.ResourceStatsResponse.error:type_name -> resource.ErrorResult - 46, // 22: resource.ResourceStatsResponse.stats:type_name -> resource.ResourceStatsResponse.Stats + 47, // 22: resource.ResourceStatsResponse.stats:type_name -> resource.ResourceStatsResponse.Stats 20, // 23: resource.ResourceSearchRequest.options:type_name -> resource.ListOptions 5, // 24: resource.ResourceSearchRequest.federated:type_name -> resource.ResourceKey - 47, // 25: resource.ResourceSearchRequest.sortBy:type_name -> resource.ResourceSearchRequest.Sort - 49, // 26: resource.ResourceSearchRequest.facet:type_name -> resource.ResourceSearchRequest.FacetEntry + 48, // 25: resource.ResourceSearchRequest.sortBy:type_name -> resource.ResourceSearchRequest.Sort + 50, // 26: resource.ResourceSearchRequest.facet:type_name -> resource.ResourceSearchRequest.FacetEntry 8, // 27: resource.ResourceSearchResponse.error:type_name -> resource.ErrorResult 5, // 28: resource.ResourceSearchResponse.key:type_name -> resource.ResourceKey - 36, // 29: resource.ResourceSearchResponse.results:type_name -> resource.ResourceTable - 52, // 30: resource.ResourceSearchResponse.facet:type_name -> resource.ResourceSearchResponse.FacetEntry + 37, // 29: resource.ResourceSearchResponse.results:type_name -> resource.ResourceTable + 53, // 30: resource.ResourceSearchResponse.facet:type_name -> resource.ResourceSearchResponse.FacetEntry 5, // 31: resource.HistoryRequest.key:type_name -> resource.ResourceKey 7, // 32: resource.HistoryResponse.items:type_name -> resource.ResourceMeta 8, // 33: resource.HistoryResponse.error:type_name -> resource.ErrorResult - 5, // 34: resource.OriginRequest.key:type_name -> resource.ResourceKey - 5, // 35: resource.ResourceOriginInfo.key:type_name -> resource.ResourceKey - 32, // 36: resource.OriginResponse.items:type_name -> resource.ResourceOriginInfo - 8, // 37: resource.OriginResponse.error:type_name -> resource.ErrorResult - 2, // 38: resource.HealthCheckResponse.status:type_name -> resource.HealthCheckResponse.ServingStatus - 37, // 39: resource.ResourceTable.columns:type_name -> resource.ResourceTableColumnDefinition - 38, // 40: resource.ResourceTable.rows:type_name -> resource.ResourceTableRow - 3, // 41: resource.ResourceTableColumnDefinition.type:type_name -> resource.ResourceTableColumnDefinition.ColumnType - 53, // 42: resource.ResourceTableColumnDefinition.properties:type_name -> resource.ResourceTableColumnDefinition.Properties - 5, // 43: resource.ResourceTableRow.key:type_name -> resource.ResourceKey - 5, // 44: resource.RestoreRequest.key:type_name -> resource.ResourceKey - 8, // 45: resource.RestoreResponse.error:type_name -> resource.ErrorResult - 5, // 46: resource.PutBlobRequest.resource:type_name -> resource.ResourceKey - 4, // 47: resource.PutBlobRequest.method:type_name -> resource.PutBlobRequest.Method - 8, // 48: resource.PutBlobResponse.error:type_name -> resource.ErrorResult - 5, // 49: resource.GetBlobRequest.resource:type_name -> resource.ResourceKey - 8, // 50: resource.GetBlobResponse.error:type_name -> resource.ErrorResult - 48, // 51: resource.ResourceSearchRequest.FacetEntry.value:type_name -> resource.ResourceSearchRequest.Facet - 51, // 52: resource.ResourceSearchResponse.Facet.terms:type_name -> resource.ResourceSearchResponse.TermFacet - 50, // 53: resource.ResourceSearchResponse.FacetEntry.value:type_name -> resource.ResourceSearchResponse.Facet - 17, // 54: resource.ResourceStore.Read:input_type -> resource.ReadRequest - 11, // 55: resource.ResourceStore.Create:input_type -> resource.CreateRequest - 13, // 56: resource.ResourceStore.Update:input_type -> resource.UpdateRequest - 15, // 57: resource.ResourceStore.Delete:input_type -> resource.DeleteRequest - 39, // 58: resource.ResourceStore.Restore:input_type -> resource.RestoreRequest - 21, // 59: resource.ResourceStore.List:input_type -> resource.ListRequest - 23, // 60: resource.ResourceStore.Watch:input_type -> resource.WatchRequest - 27, // 61: resource.ResourceIndex.Search:input_type -> resource.ResourceSearchRequest - 25, // 62: resource.ResourceIndex.GetStats:input_type -> resource.ResourceStatsRequest - 29, // 63: resource.ResourceIndex.History:input_type -> resource.HistoryRequest - 31, // 64: resource.ResourceIndex.Origin:input_type -> resource.OriginRequest - 41, // 65: resource.BlobStore.PutBlob:input_type -> resource.PutBlobRequest - 43, // 66: resource.BlobStore.GetBlob:input_type -> resource.GetBlobRequest - 34, // 67: resource.Diagnostics.IsHealthy:input_type -> resource.HealthCheckRequest - 18, // 68: resource.ResourceStore.Read:output_type -> resource.ReadResponse - 12, // 69: resource.ResourceStore.Create:output_type -> resource.CreateResponse - 14, // 70: resource.ResourceStore.Update:output_type -> resource.UpdateResponse - 16, // 71: resource.ResourceStore.Delete:output_type -> resource.DeleteResponse - 40, // 72: resource.ResourceStore.Restore:output_type -> resource.RestoreResponse - 22, // 73: resource.ResourceStore.List:output_type -> resource.ListResponse - 24, // 74: resource.ResourceStore.Watch:output_type -> resource.WatchEvent - 28, // 75: resource.ResourceIndex.Search:output_type -> resource.ResourceSearchResponse - 26, // 76: resource.ResourceIndex.GetStats:output_type -> resource.ResourceStatsResponse - 30, // 77: resource.ResourceIndex.History:output_type -> resource.HistoryResponse - 33, // 78: resource.ResourceIndex.Origin:output_type -> resource.OriginResponse - 42, // 79: resource.BlobStore.PutBlob:output_type -> resource.PutBlobResponse - 44, // 80: resource.BlobStore.GetBlob:output_type -> resource.GetBlobResponse - 35, // 81: resource.Diagnostics.IsHealthy:output_type -> resource.HealthCheckResponse - 68, // [68:82] is the sub-list for method output_type - 54, // [54:68] is the sub-list for method input_type - 54, // [54:54] is the sub-list for extension type_name - 54, // [54:54] is the sub-list for extension extendee - 0, // [0:54] is the sub-list for field type_name + 5, // 34: resource.ListRepositoryObjectsRequest.key:type_name -> resource.ResourceKey + 54, // 35: resource.ListRepositoryObjectsResponse.items:type_name -> resource.ListRepositoryObjectsResponse.Item + 8, // 36: resource.ListRepositoryObjectsResponse.error:type_name -> resource.ErrorResult + 56, // 37: resource.CountRepositoryObjectsResponse.stats:type_name -> resource.CountRepositoryObjectsResponse.StatsEntry + 8, // 38: resource.CountRepositoryObjectsResponse.error:type_name -> resource.ErrorResult + 2, // 39: resource.HealthCheckResponse.status:type_name -> resource.HealthCheckResponse.ServingStatus + 38, // 40: resource.ResourceTable.columns:type_name -> resource.ResourceTableColumnDefinition + 39, // 41: resource.ResourceTable.rows:type_name -> resource.ResourceTableRow + 3, // 42: resource.ResourceTableColumnDefinition.type:type_name -> resource.ResourceTableColumnDefinition.ColumnType + 57, // 43: resource.ResourceTableColumnDefinition.properties:type_name -> resource.ResourceTableColumnDefinition.Properties + 5, // 44: resource.ResourceTableRow.key:type_name -> resource.ResourceKey + 5, // 45: resource.RestoreRequest.key:type_name -> resource.ResourceKey + 8, // 46: resource.RestoreResponse.error:type_name -> resource.ErrorResult + 5, // 47: resource.PutBlobRequest.resource:type_name -> resource.ResourceKey + 4, // 48: resource.PutBlobRequest.method:type_name -> resource.PutBlobRequest.Method + 8, // 49: resource.PutBlobResponse.error:type_name -> resource.ErrorResult + 5, // 50: resource.GetBlobRequest.resource:type_name -> resource.ResourceKey + 8, // 51: resource.GetBlobResponse.error:type_name -> resource.ErrorResult + 49, // 52: resource.ResourceSearchRequest.FacetEntry.value:type_name -> resource.ResourceSearchRequest.Facet + 52, // 53: resource.ResourceSearchResponse.Facet.terms:type_name -> resource.ResourceSearchResponse.TermFacet + 51, // 54: resource.ResourceSearchResponse.FacetEntry.value:type_name -> resource.ResourceSearchResponse.Facet + 5, // 55: resource.ListRepositoryObjectsResponse.Item.object:type_name -> resource.ResourceKey + 55, // 56: resource.CountRepositoryObjectsResponse.StatsEntry.value:type_name -> resource.CountRepositoryObjectsResponse.KindCount + 17, // 57: resource.ResourceStore.Read:input_type -> resource.ReadRequest + 11, // 58: resource.ResourceStore.Create:input_type -> resource.CreateRequest + 13, // 59: resource.ResourceStore.Update:input_type -> resource.UpdateRequest + 15, // 60: resource.ResourceStore.Delete:input_type -> resource.DeleteRequest + 40, // 61: resource.ResourceStore.Restore:input_type -> resource.RestoreRequest + 21, // 62: resource.ResourceStore.List:input_type -> resource.ListRequest + 23, // 63: resource.ResourceStore.Watch:input_type -> resource.WatchRequest + 27, // 64: resource.ResourceIndex.Search:input_type -> resource.ResourceSearchRequest + 25, // 65: resource.ResourceIndex.GetStats:input_type -> resource.ResourceStatsRequest + 29, // 66: resource.ResourceIndex.History:input_type -> resource.HistoryRequest + 33, // 67: resource.RepositoryIndex.CountRepositoryObjects:input_type -> resource.CountRepositoryObjectsRequest + 31, // 68: resource.RepositoryIndex.ListRepositoryObjects:input_type -> resource.ListRepositoryObjectsRequest + 42, // 69: resource.BlobStore.PutBlob:input_type -> resource.PutBlobRequest + 44, // 70: resource.BlobStore.GetBlob:input_type -> resource.GetBlobRequest + 35, // 71: resource.Diagnostics.IsHealthy:input_type -> resource.HealthCheckRequest + 18, // 72: resource.ResourceStore.Read:output_type -> resource.ReadResponse + 12, // 73: resource.ResourceStore.Create:output_type -> resource.CreateResponse + 14, // 74: resource.ResourceStore.Update:output_type -> resource.UpdateResponse + 16, // 75: resource.ResourceStore.Delete:output_type -> resource.DeleteResponse + 41, // 76: resource.ResourceStore.Restore:output_type -> resource.RestoreResponse + 22, // 77: resource.ResourceStore.List:output_type -> resource.ListResponse + 24, // 78: resource.ResourceStore.Watch:output_type -> resource.WatchEvent + 28, // 79: resource.ResourceIndex.Search:output_type -> resource.ResourceSearchResponse + 26, // 80: resource.ResourceIndex.GetStats:output_type -> resource.ResourceStatsResponse + 30, // 81: resource.ResourceIndex.History:output_type -> resource.HistoryResponse + 34, // 82: resource.RepositoryIndex.CountRepositoryObjects:output_type -> resource.CountRepositoryObjectsResponse + 32, // 83: resource.RepositoryIndex.ListRepositoryObjects:output_type -> resource.ListRepositoryObjectsResponse + 43, // 84: resource.BlobStore.PutBlob:output_type -> resource.PutBlobResponse + 45, // 85: resource.BlobStore.GetBlob:output_type -> resource.GetBlobResponse + 36, // 86: resource.Diagnostics.IsHealthy:output_type -> resource.HealthCheckResponse + 72, // [72:87] is the sub-list for method output_type + 57, // [57:72] is the sub-list for method input_type + 57, // [57:57] is the sub-list for extension type_name + 57, // [57:57] is the sub-list for extension extendee + 0, // [0:57] is the sub-list for field type_name } func init() { file_resource_proto_init() } @@ -4374,9 +4576,9 @@ func file_resource_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_resource_proto_rawDesc, NumEnums: 5, - NumMessages: 49, + NumMessages: 53, NumExtensions: 0, - NumServices: 4, + NumServices: 5, }, GoTypes: file_resource_proto_goTypes, DependencyIndexes: file_resource_proto_depIdxs, diff --git a/pkg/storage/unified/resource/resource.proto b/pkg/storage/unified/resource/resource.proto index 48df551d2f0..66d84e5c4a8 100644 --- a/pkg/storage/unified/resource/resource.proto +++ b/pkg/storage/unified/resource/resource.proto @@ -470,54 +470,76 @@ message HistoryResponse { ErrorResult error = 4; } -message OriginRequest { +// List items within a resource type & repository name +// Access control is managed above this request +message ListRepositoryObjectsRequest { // Starting from the requested page (other query parameters must match!) string next_page_token = 1; + // All results exist within this resource namespace+name + ResourceKey key = 2; + + // The name of the repository + string name = 3; + // Maximum number of items to return - int64 limit = 2; - - // Resource identifier - ResourceKey key = 3; - - // List the deleted values (eg, show trash) - string origin = 4; + int64 limit = 4; } -message ResourceOriginInfo { - // The resource - ResourceKey key = 1; +message ListRepositoryObjectsResponse { + message Item { + // The resource object key + ResourceKey object = 1; - // Size of the full resource body - int32 resource_size = 2; + // Hash for the resource + string path = 2; + + // Verification hash from the origin + string hash = 3; + + // Change time from the origin + int64 time = 5; - // Hash for the resource - string resource_hash = 3; + // Title inside the payload + string title = 6; + + // The name of the folder in metadata + string folder = 7; + } - // The origin name - string origin = 4; - - // Path on the origin - string path = 5; - - // Verification hash from the origin - string hash = 6; - - // Change time from the origin - int64 timestamp = 7; -} - -message OriginResponse { - repeated ResourceOriginInfo items = 1; + // Item iterator + repeated Item items = 1; // More results exist... pass this in the next request string next_page_token = 2; - // ResourceVersion of the list response - int64 resource_version = 3; + // Error details + ErrorResult error = 3; +} + +// Count the items that exist with +message CountRepositoryObjectsRequest { + // Namespace (tenant) + string namespace = 1; + + // The name of the repository + // (eventually empty to count across all repositories) + string repository = 2; +} + +// Count the items that exist with +message CountRepositoryObjectsResponse { + message KindCount { + string group = 1; + string resource = 2; + int64 count = 3; + } + + // Stats keyed by the repository name + map stats = 1; // Error details - ErrorResult error = 4; + ErrorResult error = 2; } message HealthCheckRequest { @@ -609,7 +631,7 @@ message ResourceTableColumnDefinition { // Defines the column type. In k8s, this will resolve into both the type and format fields ColumnType type = 2; - // The value is an arry of given type + // The value is an array of given type bool is_array = 3; // description is a human readable description of this column. @@ -774,9 +796,16 @@ service ResourceIndex { // Show resource history (and trash) rpc History(HistoryRequest) returns (HistoryResponse); +} - // Used for efficient provisioning - rpc Origin(OriginRequest) returns (OriginResponse); +// Query repository info from the search index. +// Results access control is based on access to the repository *not* the items +service RepositoryIndex { + // Describe how many resources of each type exist within a repository + rpc CountRepositoryObjects(CountRepositoryObjectsRequest) returns (CountRepositoryObjectsResponse); + + // List the resources of a specific kind within a repository + rpc ListRepositoryObjects(ListRepositoryObjectsRequest) returns (ListRepositoryObjectsResponse); } service BlobStore { diff --git a/pkg/storage/unified/resource/resource_grpc.pb.go b/pkg/storage/unified/resource/resource_grpc.pb.go index d0524f923f0..b71291d9153 100644 --- a/pkg/storage/unified/resource/resource_grpc.pb.go +++ b/pkg/storage/unified/resource/resource_grpc.pb.go @@ -389,7 +389,6 @@ const ( ResourceIndex_Search_FullMethodName = "/resource.ResourceIndex/Search" ResourceIndex_GetStats_FullMethodName = "/resource.ResourceIndex/GetStats" ResourceIndex_History_FullMethodName = "/resource.ResourceIndex/History" - ResourceIndex_Origin_FullMethodName = "/resource.ResourceIndex/Origin" ) // ResourceIndexClient is the client API for ResourceIndex service. @@ -404,8 +403,6 @@ type ResourceIndexClient interface { GetStats(ctx context.Context, in *ResourceStatsRequest, opts ...grpc.CallOption) (*ResourceStatsResponse, error) // Show resource history (and trash) History(ctx context.Context, in *HistoryRequest, opts ...grpc.CallOption) (*HistoryResponse, error) - // Used for efficient provisioning - Origin(ctx context.Context, in *OriginRequest, opts ...grpc.CallOption) (*OriginResponse, error) } type resourceIndexClient struct { @@ -446,16 +443,6 @@ func (c *resourceIndexClient) History(ctx context.Context, in *HistoryRequest, o return out, nil } -func (c *resourceIndexClient) Origin(ctx context.Context, in *OriginRequest, opts ...grpc.CallOption) (*OriginResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(OriginResponse) - err := c.cc.Invoke(ctx, ResourceIndex_Origin_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - // ResourceIndexServer is the server API for ResourceIndex service. // All implementations should embed UnimplementedResourceIndexServer // for forward compatibility @@ -468,8 +455,6 @@ type ResourceIndexServer interface { GetStats(context.Context, *ResourceStatsRequest) (*ResourceStatsResponse, error) // Show resource history (and trash) History(context.Context, *HistoryRequest) (*HistoryResponse, error) - // Used for efficient provisioning - Origin(context.Context, *OriginRequest) (*OriginResponse, error) } // UnimplementedResourceIndexServer should be embedded to have forward compatible implementations. @@ -485,9 +470,6 @@ func (UnimplementedResourceIndexServer) GetStats(context.Context, *ResourceStats func (UnimplementedResourceIndexServer) History(context.Context, *HistoryRequest) (*HistoryResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method History not implemented") } -func (UnimplementedResourceIndexServer) Origin(context.Context, *OriginRequest) (*OriginResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Origin not implemented") -} // UnsafeResourceIndexServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ResourceIndexServer will @@ -554,24 +536,6 @@ func _ResourceIndex_History_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } -func _ResourceIndex_Origin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(OriginRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ResourceIndexServer).Origin(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: ResourceIndex_Origin_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ResourceIndexServer).Origin(ctx, req.(*OriginRequest)) - } - return interceptor(ctx, in, info, handler) -} - // ResourceIndex_ServiceDesc is the grpc.ServiceDesc for ResourceIndex service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -591,9 +555,142 @@ var ResourceIndex_ServiceDesc = grpc.ServiceDesc{ MethodName: "History", Handler: _ResourceIndex_History_Handler, }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "resource.proto", +} + +const ( + RepositoryIndex_CountRepositoryObjects_FullMethodName = "/resource.RepositoryIndex/CountRepositoryObjects" + RepositoryIndex_ListRepositoryObjects_FullMethodName = "/resource.RepositoryIndex/ListRepositoryObjects" +) + +// RepositoryIndexClient is the client API for RepositoryIndex service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Query repository info from the search index. +// Results access control is based on access to the repository *not* the items +type RepositoryIndexClient interface { + // Describe how many resources of each type exist within a repository + CountRepositoryObjects(ctx context.Context, in *CountRepositoryObjectsRequest, opts ...grpc.CallOption) (*CountRepositoryObjectsResponse, error) + // List the resources of a specific kind within a repository + ListRepositoryObjects(ctx context.Context, in *ListRepositoryObjectsRequest, opts ...grpc.CallOption) (*ListRepositoryObjectsResponse, error) +} + +type repositoryIndexClient struct { + cc grpc.ClientConnInterface +} + +func NewRepositoryIndexClient(cc grpc.ClientConnInterface) RepositoryIndexClient { + return &repositoryIndexClient{cc} +} + +func (c *repositoryIndexClient) CountRepositoryObjects(ctx context.Context, in *CountRepositoryObjectsRequest, opts ...grpc.CallOption) (*CountRepositoryObjectsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CountRepositoryObjectsResponse) + err := c.cc.Invoke(ctx, RepositoryIndex_CountRepositoryObjects_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *repositoryIndexClient) ListRepositoryObjects(ctx context.Context, in *ListRepositoryObjectsRequest, opts ...grpc.CallOption) (*ListRepositoryObjectsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListRepositoryObjectsResponse) + err := c.cc.Invoke(ctx, RepositoryIndex_ListRepositoryObjects_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// RepositoryIndexServer is the server API for RepositoryIndex service. +// All implementations should embed UnimplementedRepositoryIndexServer +// for forward compatibility +// +// Query repository info from the search index. +// Results access control is based on access to the repository *not* the items +type RepositoryIndexServer interface { + // Describe how many resources of each type exist within a repository + CountRepositoryObjects(context.Context, *CountRepositoryObjectsRequest) (*CountRepositoryObjectsResponse, error) + // List the resources of a specific kind within a repository + ListRepositoryObjects(context.Context, *ListRepositoryObjectsRequest) (*ListRepositoryObjectsResponse, error) +} + +// UnimplementedRepositoryIndexServer should be embedded to have forward compatible implementations. +type UnimplementedRepositoryIndexServer struct { +} + +func (UnimplementedRepositoryIndexServer) CountRepositoryObjects(context.Context, *CountRepositoryObjectsRequest) (*CountRepositoryObjectsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CountRepositoryObjects not implemented") +} +func (UnimplementedRepositoryIndexServer) ListRepositoryObjects(context.Context, *ListRepositoryObjectsRequest) (*ListRepositoryObjectsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListRepositoryObjects not implemented") +} + +// UnsafeRepositoryIndexServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to RepositoryIndexServer will +// result in compilation errors. +type UnsafeRepositoryIndexServer interface { + mustEmbedUnimplementedRepositoryIndexServer() +} + +func RegisterRepositoryIndexServer(s grpc.ServiceRegistrar, srv RepositoryIndexServer) { + s.RegisterService(&RepositoryIndex_ServiceDesc, srv) +} + +func _RepositoryIndex_CountRepositoryObjects_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CountRepositoryObjectsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RepositoryIndexServer).CountRepositoryObjects(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: RepositoryIndex_CountRepositoryObjects_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RepositoryIndexServer).CountRepositoryObjects(ctx, req.(*CountRepositoryObjectsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RepositoryIndex_ListRepositoryObjects_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListRepositoryObjectsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RepositoryIndexServer).ListRepositoryObjects(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: RepositoryIndex_ListRepositoryObjects_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RepositoryIndexServer).ListRepositoryObjects(ctx, req.(*ListRepositoryObjectsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// RepositoryIndex_ServiceDesc is the grpc.ServiceDesc for RepositoryIndex service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var RepositoryIndex_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "resource.RepositoryIndex", + HandlerType: (*RepositoryIndexServer)(nil), + Methods: []grpc.MethodDesc{ { - MethodName: "Origin", - Handler: _ResourceIndex_Origin_Handler, + MethodName: "CountRepositoryObjects", + Handler: _RepositoryIndex_CountRepositoryObjects_Handler, + }, + { + MethodName: "ListRepositoryObjects", + Handler: _RepositoryIndex_ListRepositoryObjects_Handler, }, }, Streams: []grpc.StreamDesc{}, diff --git a/pkg/storage/unified/resource/search.go b/pkg/storage/unified/resource/search.go index 87a20e69a69..6e9f44551f3 100644 --- a/pkg/storage/unified/resource/search.go +++ b/pkg/storage/unified/resource/search.go @@ -43,9 +43,11 @@ type ResourceIndex interface { // When working with federated queries, the additional indexes will be passed in explicitly Search(ctx context.Context, access authz.AccessClient, req *ResourceSearchRequest, federate []ResourceIndex) (*ResourceSearchResponse, error) - // Execute an origin query -- access control is not not checked for each item - // NOTE: this will likely be used for provisioning, or it will be removed - Origin(ctx context.Context, req *OriginRequest) (*OriginResponse, error) + // List within an response + ListRepositoryObjects(ctx context.Context, req *ListRepositoryObjectsRequest) (*ListRepositoryObjectsResponse, error) + + // Counts the values in a repo + CountRepositoryObjects(ctx context.Context) (map[string]int64, error) // Get the number of documents in the index DocCount(ctx context.Context, folder string) (int64, error) @@ -93,7 +95,8 @@ type searchSupport struct { } var ( - _ ResourceIndexServer = (*searchSupport)(nil) + _ ResourceIndexServer = (*searchSupport)(nil) + _ RepositoryIndexServer = (*searchSupport)(nil) ) func newSearchSupport(opts SearchOptions, storage StorageBackend, access authz.AccessClient, blob BlobSupport, tracer trace.Tracer) (support *searchSupport, err error) { @@ -131,12 +134,25 @@ func newSearchSupport(opts SearchOptions, storage StorageBackend, access authz.A // History implements ResourceIndexServer. func (s *searchSupport) History(context.Context, *HistoryRequest) (*HistoryResponse, error) { - return nil, fmt.Errorf("not implemented yet... likely should not be the serarch server") + return nil, fmt.Errorf("not implemented yet... likely should not be the search server") } -// Origin implements ResourceIndexServer. -func (s *searchSupport) Origin(context.Context, *OriginRequest) (*OriginResponse, error) { - return nil, fmt.Errorf("TBD.. rename to repository") +func (s *searchSupport) ListRepositoryObjects(ctx context.Context, req *ListRepositoryObjectsRequest) (*ListRepositoryObjectsResponse, error) { + idx, err := s.getOrCreateIndex(ctx, NamespacedResource{ + Group: req.Key.Group, + Namespace: req.Key.Namespace, + Resource: req.Key.Resource, + }) + if err != nil { + return &ListRepositoryObjectsResponse{ + Error: AsErrorResult(err), + }, nil + } + return idx.ListRepositoryObjects(ctx, req) +} + +func (s *searchSupport) CountRepositoryObjects(context.Context, *CountRepositoryObjectsRequest) (*CountRepositoryObjectsResponse, error) { + return nil, fmt.Errorf("not implemented yet... requires iterating kinds") } // Search implements ResourceIndexServer. diff --git a/pkg/storage/unified/resource/server.go b/pkg/storage/unified/resource/server.go index 1494a824746..cc16bf64814 100644 --- a/pkg/storage/unified/resource/server.go +++ b/pkg/storage/unified/resource/server.go @@ -29,6 +29,7 @@ import ( type ResourceServer interface { ResourceStoreServer ResourceIndexServer + RepositoryIndexServer BlobStoreServer DiagnosticsServer } @@ -1073,9 +1074,12 @@ func (s *server) History(ctx context.Context, req *HistoryRequest) (*HistoryResp return s.search.History(ctx, req) } -// Origin implements ResourceServer. -func (s *server) Origin(ctx context.Context, req *OriginRequest) (*OriginResponse, error) { - return s.search.Origin(ctx, req) +func (s *server) ListRepositoryObjects(ctx context.Context, req *ListRepositoryObjectsRequest) (*ListRepositoryObjectsResponse, error) { + return s.search.ListRepositoryObjects(ctx, req) +} + +func (s *server) CountRepositoryObjects(ctx context.Context, req *CountRepositoryObjectsRequest) (*CountRepositoryObjectsResponse, error) { + return s.search.CountRepositoryObjects(ctx, req) } // IsHealthy implements ResourceServer. diff --git a/pkg/storage/unified/search/bleve.go b/pkg/storage/unified/search/bleve.go index c103305d45b..7baa748c05a 100644 --- a/pkg/storage/unified/search/bleve.go +++ b/pkg/storage/unified/search/bleve.go @@ -245,9 +245,108 @@ func (b *bleveIndex) Flush() (err error) { return err } -// Origin implements resource.DocumentIndex. -func (b *bleveIndex) Origin(ctx context.Context, req *resource.OriginRequest) (*resource.OriginResponse, error) { - panic("unimplemented") +func (b *bleveIndex) ListRepositoryObjects(ctx context.Context, req *resource.ListRepositoryObjectsRequest) (*resource.ListRepositoryObjectsResponse, error) { + if req.NextPageToken != "" { + return nil, fmt.Errorf("next page not implemented yet") + } + + size := 1000000000 // big number + if req.Limit > 0 { + size = int(req.Limit) + } + + found, err := b.index.SearchInContext(ctx, &bleve.SearchRequest{ + Query: &query.TermQuery{ + Term: req.Name, + FieldVal: resource.SEARCH_FIELD_REPOSITORY_NAME, + }, + Fields: []string{ + resource.SEARCH_FIELD_TITLE, + resource.SEARCH_FIELD_FOLDER, + resource.SEARCH_FIELD_REPOSITORY_NAME, + resource.SEARCH_FIELD_REPOSITORY_PATH, + resource.SEARCH_FIELD_REPOSITORY_HASH, + resource.SEARCH_FIELD_REPOSITORY_TIME, + }, + Sort: search.SortOrder{ + &search.SortField{ + Field: resource.SEARCH_FIELD_REPOSITORY_PATH, + Type: search.SortFieldAsString, + Desc: false, + }, + }, + Size: size, + From: 0, // TODO! next page token!!! + }) + if err != nil { + return nil, err + } + + asString := func(v any) string { + if v == nil { + return "" + } + str, ok := v.(string) + if ok { + return str + } + return fmt.Sprintf("%v", v) + } + + asTime := func(v any) int64 { + if v == nil { + return 0 + } + intV, ok := v.(int64) + if ok { + return intV + } + str, ok := v.(string) + if ok { + t, _ := time.Parse(time.RFC3339, str) + return t.UnixMilli() + } + return 0 + } + + rsp := &resource.ListRepositoryObjectsResponse{} + for _, hit := range found.Hits { + item := &resource.ListRepositoryObjectsResponse_Item{ + Object: &resource.ResourceKey{}, + Hash: asString(hit.Fields[resource.SEARCH_FIELD_REPOSITORY_HASH]), + Path: asString(hit.Fields[resource.SEARCH_FIELD_REPOSITORY_PATH]), + Time: asTime(hit.Fields[resource.SEARCH_FIELD_REPOSITORY_TIME]), + Title: asString(hit.Fields[resource.SEARCH_FIELD_TITLE]), + Folder: asString(hit.Fields[resource.SEARCH_FIELD_FOLDER]), + } + err := item.Object.ReadSearchID(hit.ID) + if err != nil { + return nil, err + } + rsp.Items = append(rsp.Items, item) + } + return rsp, nil +} + +func (b *bleveIndex) CountRepositoryObjects(ctx context.Context) (map[string]int64, error) { + found, err := b.index.SearchInContext(ctx, &bleve.SearchRequest{ + Query: bleve.NewMatchAllQuery(), + Size: 0, + Facets: bleve.FacetsRequest{ + "count": bleve.NewFacetRequest(resource.SEARCH_FIELD_REPOSITORY_NAME, 1000), // typically less then 5 + }, + }) + if err != nil { + return nil, err + } + rsp := make(map[string]int64) + f, ok := found.Facets["count"] + if ok && f.Terms != nil { + for _, v := range f.Terms.Terms() { + rsp[v.Term] = int64(v.Count) + } + } + return rsp, nil } // Search implements resource.DocumentIndex. diff --git a/pkg/storage/unified/search/bleve_mappings.go b/pkg/storage/unified/search/bleve_mappings.go index 3fb044e7a3b..f9cdafc41d4 100644 --- a/pkg/storage/unified/search/bleve_mappings.go +++ b/pkg/storage/unified/search/bleve_mappings.go @@ -67,17 +67,38 @@ func getBleveDocMappings(_ resource.SearchableDocumentFields) *mapping.DocumentM } mapper.AddFieldMappingsAt(resource.SEARCH_FIELD_FOLDER, folderMapping) - repoMapping := &mapping.FieldMapping{ - Name: resource.SEARCH_FIELD_REPOSITORY, + // Repositories + repo := bleve.NewDocumentStaticMapping() + repo.AddFieldMappingsAt("name", &mapping.FieldMapping{ + Name: "name", Type: "text", Analyzer: keyword.Name, Store: true, Index: true, IncludeTermVectors: false, IncludeInAll: true, - DocValues: true, - } - mapper.AddFieldMappingsAt(resource.SEARCH_FIELD_REPOSITORY, repoMapping) + }) + repo.AddFieldMappingsAt("path", &mapping.FieldMapping{ + Name: "path", + Type: "text", + Analyzer: keyword.Name, + Store: true, + Index: true, + IncludeTermVectors: false, + IncludeInAll: true, + }) + repo.AddFieldMappingsAt("hash", &mapping.FieldMapping{ + Name: "hash", + Type: "text", + Analyzer: keyword.Name, + Store: true, + Index: true, + IncludeTermVectors: false, + IncludeInAll: true, + }) + repo.AddFieldMappingsAt("time", mapping.NewDateTimeFieldMapping()) + + mapper.AddSubDocumentMapping("repo", repo) labelMapper := bleve.NewDocumentMapping() mapper.AddSubDocumentMapping(resource.SEARCH_FIELD_LABELS, labelMapper) diff --git a/pkg/storage/unified/search/bleve_mappings_test.go b/pkg/storage/unified/search/bleve_mappings_test.go index 2f289dea756..d1a07fdf116 100644 --- a/pkg/storage/unified/search/bleve_mappings_test.go +++ b/pkg/storage/unified/search/bleve_mappings_test.go @@ -26,9 +26,10 @@ func TestDocumentMapping(t *testing.T) { }, RV: 1234, RepoInfo: &utils.ResourceRepositoryInfo{ - Name: "nnn", - Path: "ppp", - Hash: "hhh", + Name: "nnn", + Path: "ppp", + Hash: "hhh", + Timestamp: asTimePointer(1234), }, } @@ -42,5 +43,5 @@ func TestDocumentMapping(t *testing.T) { fmt.Printf("DOC: fields %d\n", len(doc.Fields)) fmt.Printf("DOC: size %d\n", doc.Size()) - require.Equal(t, 12, len(doc.Fields)) + require.Equal(t, 13, len(doc.Fields)) } diff --git a/pkg/storage/unified/search/bleve_test.go b/pkg/storage/unified/search/bleve_test.go index b20287a3169..7cf2f765a20 100644 --- a/pkg/storage/unified/search/bleve_test.go +++ b/pkg/storage/unified/search/bleve_test.go @@ -3,9 +3,11 @@ package search import ( "context" "encoding/json" + "fmt" "os" "path/filepath" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -82,6 +84,12 @@ func TestBleveBackend(t *testing.T) { utils.LabelKeyDeprecatedInternalID: "10", // nolint:staticcheck }, Tags: []string{"aa", "bb"}, + RepoInfo: &utils.ResourceRepositoryInfo{ + Name: "repo-1", + Path: "path/to/aaa.json", + Hash: "xyz", + Timestamp: asTimePointer(1609462800000), // 2021 + }, }) _ = index.Write(&resource.IndexableDocument{ RV: 2, @@ -105,6 +113,12 @@ func TestBleveBackend(t *testing.T) { "region": "east", utils.LabelKeyDeprecatedInternalID: "11", // nolint:staticcheck }, + RepoInfo: &utils.ResourceRepositoryInfo{ + Name: "repo-1", + Path: "path/to/bbb.json", + Hash: "hijk", + Timestamp: asTimePointer(1640998800000), // 2022 + }, }) _ = index.Write(&resource.IndexableDocument{ RV: 3, @@ -119,7 +133,8 @@ func TestBleveBackend(t *testing.T) { TitleSort: "ccc (dash)", Folder: "zzz", RepoInfo: &utils.ResourceRepositoryInfo{ - Name: "r0", + Name: "repo2", + Path: "path/in/repo2.yaml", }, Fields: map[string]any{ DASHBOARD_LEGACY_ID: 12, @@ -201,6 +216,53 @@ func TestBleveBackend(t *testing.T) { rsp.Results.Rows[0].Key.Name, rsp.Results.Rows[1].Key.Name, }) + + // Now look for repositories + found, err := index.ListRepositoryObjects(ctx, &resource.ListRepositoryObjectsRequest{ + Name: "repo-1", + Limit: 100, + }) + require.NoError(t, err) + jj, err := json.MarshalIndent(found, "", " ") + require.NoError(t, err) + fmt.Printf("%s\n", string(jj)) + require.JSONEq(t, `{ + "items": [ + { + "object": { + "namespace": "ns", + "group": "dashboard.grafana.app", + "resource": "dashboards", + "name": "aaa" + }, + "path": "path/to/aaa.json", + "hash": "xyz", + "time": 1609462800000, + "title": "aaa (dash)", + "folder": "xxx" + }, + { + "object": { + "namespace": "ns", + "group": "dashboard.grafana.app", + "resource": "dashboards", + "name": "bbb" + }, + "path": "path/to/bbb.json", + "hash": "hijk", + "time": 1640998800000, + "title": "bbb (dash)", + "folder": "xxx" + } + ] + }`, string(jj)) + + counts, err := index.CountRepositoryObjects(ctx) + require.NoError(t, err) + require.Equal(t, map[string]int64{ + "repo-1": 2, + "repo2": 1, + }, counts) }) t.Run("build folders", func(t *testing.T) { @@ -222,6 +284,12 @@ func TestBleveBackend(t *testing.T) { }, Title: "zzz (folder)", TitleSort: "zzz (folder)", + RepoInfo: &utils.ResourceRepositoryInfo{ + Name: "repo-1", + Path: "path/to/folder.json", + Hash: "xxxx", + Timestamp: asTimePointer(300), + }, }) _ = index.Write(&resource.IndexableDocument{ RV: 2, @@ -327,3 +395,11 @@ func TestBleveBackend(t *testing.T) { }`, string(disp)) }) } + +func asTimePointer(milli int64) *time.Time { + if milli > 0 { + t := time.UnixMilli(milli) + return &t + } + return nil +} diff --git a/pkg/storage/unified/search/testdata/doc/folder-aaa-out.json b/pkg/storage/unified/search/testdata/doc/folder-aaa-out.json index 867c2bfa1ea..85809ce618f 100644 --- a/pkg/storage/unified/search/testdata/doc/folder-aaa-out.json +++ b/pkg/storage/unified/search/testdata/doc/folder-aaa-out.json @@ -11,7 +11,7 @@ "title_sort": "test-aaa", "created": 1730490142000, "createdBy": "user:1", - "repository": { + "repo": { "name": "SQL" } } \ No newline at end of file diff --git a/pkg/storage/unified/search/testdata/doc/folder-bbb-out.json b/pkg/storage/unified/search/testdata/doc/folder-bbb-out.json index e3dcd3021c9..dec666e5d42 100644 --- a/pkg/storage/unified/search/testdata/doc/folder-bbb-out.json +++ b/pkg/storage/unified/search/testdata/doc/folder-bbb-out.json @@ -11,7 +11,7 @@ "title_sort": "test-bbb", "created": 1730490142000, "createdBy": "user:1", - "repository": { + "repo": { "name": "SQL" } } \ No newline at end of file diff --git a/pkg/storage/unified/search/testdata/doc/playlist-aaa-out.json b/pkg/storage/unified/search/testdata/doc/playlist-aaa-out.json index 235ec31e336..a4fc4117a9a 100644 --- a/pkg/storage/unified/search/testdata/doc/playlist-aaa-out.json +++ b/pkg/storage/unified/search/testdata/doc/playlist-aaa-out.json @@ -11,7 +11,7 @@ "title_sort": "test aaa", "created": 1731336353000, "createdBy": "user:t000000001", - "repository": { + "repo": { "name": "UI", "path": "/playlists/new", "hash": "Grafana v11.4.0-pre (c0de407fee)" diff --git a/pkg/storage/unified/search/testdata/doc/report-aaa-out.json b/pkg/storage/unified/search/testdata/doc/report-aaa-out.json index 0280c35f574..26c9b3ee090 100644 --- a/pkg/storage/unified/search/testdata/doc/report-aaa-out.json +++ b/pkg/storage/unified/search/testdata/doc/report-aaa-out.json @@ -11,7 +11,7 @@ "title_sort": "test aaa", "created": 1706690655000, "createdBy": "user:abc", - "repository": { + "repo": { "name": "SQL" } } \ No newline at end of file diff --git a/pkg/storage/unified/sql/search.go b/pkg/storage/unified/sql/search.go index ba03de17e74..abdf750fd92 100644 --- a/pkg/storage/unified/sql/search.go +++ b/pkg/storage/unified/sql/search.go @@ -2,6 +2,7 @@ package sql import ( "context" + "fmt" "net/http" "github.com/grafana/grafana/pkg/storage/unified/resource" @@ -62,14 +63,12 @@ func (b *backend) History(context.Context, *resource.HistoryRequest) (*resource. }, nil } -// Origin implements resource.ResourceIndexServer. -func (b *backend) Origin(context.Context, *resource.OriginRequest) (*resource.OriginResponse, error) { - return &resource.OriginResponse{ - Error: &resource.ErrorResult{ - Code: http.StatusNotImplemented, - Message: "SQL backend does not implement Origin", - }, - }, nil +func (b *backend) RepositoryList(ctx context.Context, req *resource.ListRepositoryObjectsRequest) (*resource.ListRepositoryObjectsResponse, error) { + return nil, fmt.Errorf("SQL backend does not implement RepositoryList") +} + +func (b *backend) RepositoryStats(context.Context, *resource.CountRepositoryObjectsRequest) (*resource.CountRepositoryObjectsResponse, error) { + return nil, fmt.Errorf("SQL backend does not implement RepositoryStats") } // Search implements resource.ResourceIndexServer. From 99a0eb825d0ee07d9c83d108d70680070ea95120 Mon Sep 17 00:00:00 2001 From: Ezequiel Victorero Date: Fri, 10 Jan 2025 16:17:09 -0300 Subject: [PATCH 13/19] Revert "Share: Add analytics to invite user flow" (#98838) Revert "Share: Add analytics to invite user flow (#98617)" This reverts commit 79cd8ac894a2917312a256576cf54f540fc5c494. --- .../dashboard-scene/sharing/ShareButton/ShareMenu.tsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/public/app/features/dashboard-scene/sharing/ShareButton/ShareMenu.tsx b/public/app/features/dashboard-scene/sharing/ShareButton/ShareMenu.tsx index 124bd7e78a2..c701e2a41ec 100644 --- a/public/app/features/dashboard-scene/sharing/ShareButton/ShareMenu.tsx +++ b/public/app/features/dashboard-scene/sharing/ShareButton/ShareMenu.tsx @@ -93,14 +93,7 @@ export default function ShareMenu({ dashboard, panel }: { dashboard: DashboardSc label: t('share-dashboard.menu.invite-user-title', 'Invite new member'), renderCondition: !!config.externalUserMngLinkUrl && contextSrv.hasPermission(AccessControlAction.OrgUsersAdd), onClick: () => { - const url = new URL(config.externalUserMngLinkUrl); - - // Add query parameters to track conversion - url.searchParams.append('src', 'grafananet'); - url.searchParams.append('cnt', 'share-invite'); - - // Open the modified URL - window.open(url.toString(), '_blank'); + window.open(config.externalUserMngLinkUrl, '_blank'); }, renderDividerAbove: true, component: () => , From c9d22f06c38b8bb2dd4629db96d1760e0b49d8ff Mon Sep 17 00:00:00 2001 From: Michael Mandrus <41969079+mmandrus@users.noreply.github.com> Date: Fri, 10 Jan 2025 14:42:18 -0500 Subject: [PATCH 14/19] CloudMigrations: Bulk update local resources (#96002) * wip * make tests pass * get all tests passing * fixes * some small cleanup * fix test * convert delimiter keys to struct keys * dont execute empty sql statement * remove printlns * fix unit test * a bit more cleanup * whoops --- .../cloudmigrationimpl/cloudmigration.go | 8 +- .../cloudmigrationimpl/cloudmigration_test.go | 10 +- .../cloudmigrationimpl/snapshot_mgmt.go | 10 +- .../cloudmigrationimpl/store.go | 9 -- .../cloudmigrationimpl/xorm_store.go | 119 ++++++++++++++---- .../cloudmigrationimpl/xorm_store_test.go | 23 ++-- .../gmsclient/inmemory_client.go | 6 - pkg/services/cloudmigration/model.go | 15 ++- .../dashboards/dashboard_service_mock.go | 2 +- 9 files changed, 139 insertions(+), 63 deletions(-) diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go index fe74d5c88bb..3a8806e26af 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go @@ -612,10 +612,10 @@ func (s *Service) GetSnapshot(ctx context.Context, query cloudmigration.GetSnaps // We need to update the snapshot in our db before reporting anything if err := s.store.UpdateSnapshot(ctx, cloudmigration.UpdateSnapshotCmd{ - UID: snapshot.UID, - SessionID: sessionUid, - Status: localStatus, - Resources: resources, + UID: snapshot.UID, + SessionID: sessionUid, + Status: localStatus, + CloudResourcesToUpdate: resources, }); err != nil { return nil, fmt.Errorf("error updating snapshot status: %w", err) } diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go index 378d2546832..9bde512b504 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go @@ -114,11 +114,19 @@ func Test_GetSnapshotStatusFromGMS(t *testing.T) { assert.Equal(t, cloudmigration.SnapshotStatusCreating, snapshot.Status) assert.Never(t, func() bool { return gmsClientFake.GetSnapshotStatusCallCount() > 0 }, time.Second, 10*time.Millisecond) - // Make the status pending processing and ensure GMS gets called + // Make the status pending processing to ensure GMS gets called and initialize a resource err = s.store.UpdateSnapshot(ctx, cloudmigration.UpdateSnapshotCmd{ UID: uid, SessionID: sess.UID, Status: cloudmigration.SnapshotStatusPendingProcessing, + LocalResourcesToCreate: []cloudmigration.CloudMigrationResource{ + { + Name: "A name", + Type: cloudmigration.DatasourceDataType, + RefID: "A", + Status: cloudmigration.ItemStatusPending, + }, + }, }) assert.NoError(t, err) diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt.go b/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt.go index 1b5cb94a971..870c4949533 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt.go @@ -569,10 +569,10 @@ func (s *Service) buildSnapshot(ctx context.Context, signedInUser *user.SignedIn // update snapshot status to pending upload with retries if err := s.updateSnapshotWithRetries(ctx, cloudmigration.UpdateSnapshotCmd{ - UID: snapshotMeta.UID, - SessionID: snapshotMeta.SessionUID, - Status: cloudmigration.SnapshotStatusPendingUpload, - Resources: localSnapshotResource, + UID: snapshotMeta.UID, + SessionID: snapshotMeta.SessionUID, + Status: cloudmigration.SnapshotStatusPendingUpload, + LocalResourcesToCreate: localSnapshotResource, }); err != nil { return err } @@ -714,7 +714,7 @@ func (s *Service) updateSnapshotWithRetries(ctx context.Context, cmd cloudmigrat } return retryer.FuncComplete, nil }, maxRetries, time.Millisecond*10, time.Second*5); err != nil { - s.log.Error("failed to update snapshot status", "snapshotUid", cmd.UID, "status", cmd.Status, "num_resources", len(cmd.Resources), "error", err.Error()) + s.log.Error("failed to update snapshot status", "snapshotUid", cmd.UID, "status", cmd.Status, "num_local_resources", len(cmd.LocalResourcesToCreate), "num_cloud_resources", len(cmd.CloudResourcesToUpdate), "error", err.Error()) return fmt.Errorf("failed to update snapshot status: %w", err) } return nil diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/store.go b/pkg/services/cloudmigration/cloudmigrationimpl/store.go index f8f7dd76263..86f130a1f27 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/store.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/store.go @@ -10,19 +10,10 @@ type store interface { CreateMigrationSession(ctx context.Context, session cloudmigration.CloudMigrationSession) (*cloudmigration.CloudMigrationSession, error) GetMigrationSessionByUID(ctx context.Context, orgID int64, uid string) (*cloudmigration.CloudMigrationSession, error) GetCloudMigrationSessionList(ctx context.Context, orgID int64) ([]*cloudmigration.CloudMigrationSession, error) - // DeleteMigrationSessionByUID deletes the migration session, and all the related snapshot and resources. - // the work is done in a transaction. DeleteMigrationSessionByUID(ctx context.Context, orgID int64, uid string) (*cloudmigration.CloudMigrationSession, []cloudmigration.CloudMigrationSnapshot, error) CreateSnapshot(ctx context.Context, snapshot cloudmigration.CloudMigrationSnapshot) (string, error) UpdateSnapshot(ctx context.Context, snapshot cloudmigration.UpdateSnapshotCmd) error GetSnapshotByUID(ctx context.Context, orgID int64, sessUid, id string, resultPage int, resultLimit int) (*cloudmigration.CloudMigrationSnapshot, error) GetSnapshotList(ctx context.Context, query cloudmigration.ListSnapshotsQuery) ([]cloudmigration.CloudMigrationSnapshot, error) - - // Deleted because were not used externally - // - DeleteSnapshot(ctx context.Context, snapshotUid string) error - // - CreateUpdateSnapshotResources(ctx context.Context, snapshotUid string, resources []cloudmigration.CloudMigrationResource) error - // - GetSnapshotResources(ctx context.Context, snapshotUid string, page int, limit int) ([]cloudmigration.CloudMigrationResource, error) - // - GetSnapshotResourceStats(ctx context.Context, snapshotUid string) (*cloudmigration.SnapshotResourceStats, error) - // - DeleteSnapshotResources(ctx context.Context, snapshotUid string) error } diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go index a3b088b09a5..efbe701e51c 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go @@ -4,6 +4,7 @@ import ( "context" "encoding/base64" "fmt" + "strings" "time" "github.com/grafana/grafana/pkg/infra/db" @@ -94,6 +95,7 @@ func (ss *sqlStore) GetCloudMigrationSessionList(ctx context.Context, orgID int6 return migrations, nil } +// DeleteMigrationSessionByUID deletes the migration session, and all the related snapshot and resources the work is done in a transaction. func (ss *sqlStore) DeleteMigrationSessionByUID(ctx context.Context, orgID int64, uid string) (*cloudmigration.CloudMigrationSession, []cloudmigration.CloudMigrationSnapshot, error) { var c cloudmigration.CloudMigrationSession err := ss.db.WithDbSession(ctx, func(sess *db.Session) error { @@ -127,7 +129,7 @@ func (ss *sqlStore) DeleteMigrationSessionByUID(ctx context.Context, orgID int64 if err != nil { return fmt.Errorf("deleting snapshot resource from db: %w", err) } - err = ss.deleteSnapshot(ctx, orgID, snapshot.UID) + err = ss.deleteSnapshot(ctx, snapshot.UID) if err != nil { return fmt.Errorf("deleting snapshot from db: %w", err) } @@ -211,19 +213,26 @@ func (ss *sqlStore) UpdateSnapshot(ctx context.Context, update cloudmigration.Up } } - // Update resources if set - if len(update.Resources) > 0 { - if err := ss.createUpdateSnapshotResources(ctx, update.UID, update.Resources); err != nil { + // If local resources are set, it means we have to create them for the first time + if len(update.LocalResourcesToCreate) > 0 { + if err := ss.CreateSnapshotResources(ctx, update.UID, update.LocalResourcesToCreate); err != nil { return err } } + // If cloud resources are set, it means we have to update our resource local state + if len(update.CloudResourcesToUpdate) > 0 { + if err := ss.UpdateSnapshotResources(ctx, update.UID, update.CloudResourcesToUpdate); err != nil { + return err + } + } + return nil }) return err } -func (ss *sqlStore) deleteSnapshot(ctx context.Context, orgID int64, snapshotUid string) error { +func (ss *sqlStore) deleteSnapshot(ctx context.Context, snapshotUid string) error { return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { _, err := sess.Delete(cloudmigration.CloudMigrationSnapshot{ UID: snapshotUid, @@ -316,30 +325,90 @@ func (ss *sqlStore) GetSnapshotList(ctx context.Context, query cloudmigration.Li return snapshots, nil } -// CreateUpdateSnapshotResources either updates a migration resource for a snapshot, or creates it if it does not exist -// If the uid is not known, it uses snapshot_uid + resource_uid as a lookup -func (ss *sqlStore) createUpdateSnapshotResources(ctx context.Context, snapshotUid string, resources []cloudmigration.CloudMigrationResource) error { +// CreateSnapshotResources initializes the local state of a resources belonging to a snapshot +func (ss *sqlStore) CreateSnapshotResources(ctx context.Context, snapshotUid string, resources []cloudmigration.CloudMigrationResource) error { + for i := 0; i < len(resources); i++ { + resources[i].UID = util.GenerateShortUID() + // ensure snapshot_uids are consistent so that we can use in conjunction with refID for lookup later + resources[i].SnapshotUID = snapshotUid + } + + err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + _, err := sess.Insert(resources) + if err != nil { + return err + } + return nil + }) + if err != nil { + return fmt.Errorf("creating resources: %w", err) + } + + return nil +} + +// UpdateSnapshotResources updates a migration resource for a snapshot, using snapshot_uid + resource_uid as a lookup +// It does preprocessing on the results in order to minimize the sql queries executed. +func (ss *sqlStore) UpdateSnapshotResources(ctx context.Context, snapshotUid string, resources []cloudmigration.CloudMigrationResource) error { + // refIds of resources that migrated successfully in order to update in bulk + okIds := make([]any, 0, len(resources)) + + // group any failed resources by errCode and errStr + type errId struct { + errCode cloudmigration.ResourceErrorCode + errStr string + } + errorIds := make(map[errId][]any) + + for _, r := range resources { + if r.Status == cloudmigration.ItemStatusOK { + okIds = append(okIds, r.RefID) + } else if r.Status == cloudmigration.ItemStatusError { + key := errId{errCode: r.ErrorCode, errStr: r.Error} + if ids, ok := errorIds[key]; ok { + errorIds[key] = append(ids, r.RefID) + } else { + errorIds[key] = []any{r.RefID} + } + } + } + + type statement struct { + sql string + args []any + } + + // Prepare a sql statement for all of the OK statuses + var okUpdateStatement *statement + if len(okIds) > 0 { + okUpdateStatement = &statement{ + sql: fmt.Sprintf("UPDATE cloud_migration_resource SET status=? WHERE snapshot_uid=? AND resource_uid IN (?%s)", strings.Repeat(", ?", len(okIds)-1)), + args: append([]any{cloudmigration.ItemStatusOK, snapshotUid}, okIds...), + } + } + + // Prepare however many sql statements are necessary for the error statuses + errorStatements := make([]statement, 0, len(errorIds)) + for k, ids := range errorIds { + errorStatements = append(errorStatements, statement{ + sql: fmt.Sprintf("UPDATE cloud_migration_resource SET status=?, error_code=?, error_string=? WHERE snapshot_uid=? AND resource_uid IN (?%s)", strings.Repeat(", ?", len(ids)-1)), + args: append([]any{cloudmigration.ItemStatusError, k.errCode, k.errStr, snapshotUid}, ids...), + }) + } + + // Execute the minimum number of required statements! + return ss.db.InTransaction(ctx, func(ctx context.Context) error { - sql := "UPDATE cloud_migration_resource SET status=?, error_string=?, error_code=? WHERE uid=? OR (snapshot_uid=? AND resource_uid=?)" err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { - for _, r := range resources { - // try an update first - result, err := sess.Exec(sql, r.Status, r.Error, r.ErrorCode, r.UID, snapshotUid, r.RefID) - if err != nil { + if okUpdateStatement != nil { + if _, err := sess.Exec(append([]any{okUpdateStatement.sql}, okUpdateStatement.args...)...); err != nil { return err } - // if this had no effect, assign a uid and insert instead - n, err := result.RowsAffected() - if err != nil { + } + + for _, q := range errorStatements { + if _, err := sess.Exec(append([]any{q.sql}, q.args...)...); err != nil { return err - } else if n == 0 { - r.UID = util.GenerateShortUID() - // ensure snapshot_uids are consistent so that we can use them to query when uid isn't known - r.SnapshotUID = snapshotUid - _, err := sess.Insert(r) - if err != nil { - return err - } } } return nil @@ -364,7 +433,7 @@ func (ss *sqlStore) getSnapshotResources(ctx context.Context, snapshotUid string err := ss.db.WithDbSession(ctx, func(sess *db.Session) error { offset := (page - 1) * limit sess.Limit(limit, offset) - return sess.Find(&resources, &cloudmigration.CloudMigrationResource{ + return sess.OrderBy("id ASC").Find(&resources, &cloudmigration.CloudMigrationResource{ SnapshotUID: snapshotUid, }) }) diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go index c9ae1163eba..03ab9065c57 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go @@ -155,7 +155,7 @@ func Test_SnapshotManagement(t *testing.T) { require.Equal(t, *snapshot, snapshots[0]) // delete snapshot - err = s.deleteSnapshot(ctx, 1, snapshotUid) + err = s.deleteSnapshot(ctx, snapshotUid) require.NoError(t, err) // now we expect not to find the snapshot @@ -174,16 +174,25 @@ func Test_SnapshotResources(t *testing.T) { resources, err := s.getSnapshotResources(ctx, "poiuy", 0, 100) assert.NoError(t, err) assert.Len(t, resources, 3) + for _, r := range resources { + if r.RefID == "ejcx4d" { + assert.Equal(t, cloudmigration.ItemStatusError, r.Status) + break + } + } - // create a new resource and update an existing resource - err = s.createUpdateSnapshotResources(ctx, "poiuy", []cloudmigration.CloudMigrationResource{ + // create a new resource + err = s.CreateSnapshotResources(ctx, "poiuy", []cloudmigration.CloudMigrationResource{ { Type: cloudmigration.DatasourceDataType, RefID: "mi39fj", Status: cloudmigration.ItemStatusOK, }, + }) + assert.NoError(t, err) + err = s.UpdateSnapshotResources(ctx, "poiuy", []cloudmigration.CloudMigrationResource{ { - UID: "qwerty", + RefID: "ejcx4d", Status: cloudmigration.ItemStatusOK, }, }) @@ -193,16 +202,16 @@ func Test_SnapshotResources(t *testing.T) { resources, err = s.getSnapshotResources(ctx, "poiuy", 0, 100) assert.NoError(t, err) assert.Len(t, resources, 4) - // ensure existing resource was updated + // ensure existing resource was updated from ERROR for _, r := range resources { - if r.UID == "querty" { + if r.RefID == "ejcx4d" { assert.Equal(t, cloudmigration.ItemStatusOK, r.Status) break } } // ensure a new one was made for _, r := range resources { - if r.UID == "mi39fj" { + if r.RefID == "mi39fj" { assert.Equal(t, cloudmigration.ItemStatusOK, r.Status) break } diff --git a/pkg/services/cloudmigration/gmsclient/inmemory_client.go b/pkg/services/cloudmigration/gmsclient/inmemory_client.go index 74cb326382d..2a9d73e0b05 100644 --- a/pkg/services/cloudmigration/gmsclient/inmemory_client.go +++ b/pkg/services/cloudmigration/gmsclient/inmemory_client.go @@ -105,12 +105,6 @@ func (c *memoryClientImpl) GetSnapshotStatus(ctx context.Context, session cloudm RefID: "folder1", Status: cloudmigration.ItemStatusOK, }, - { - Type: cloudmigration.DatasourceDataType, - RefID: "ds2", - Status: cloudmigration.ItemStatusWarning, - Error: "Only core data sources are supported. Please ensure the plugin is installed on the cloud stack.", - }, }, } diff --git a/pkg/services/cloudmigration/model.go b/pkg/services/cloudmigration/model.go index 1f6c2a54769..7d0b4b58f49 100644 --- a/pkg/services/cloudmigration/model.go +++ b/pkg/services/cloudmigration/model.go @@ -67,7 +67,7 @@ const ( type CloudMigrationResource struct { ID int64 `xorm:"pk autoincr 'id'"` - UID string `xorm:"uid"` + UID string `xorm:"uid" json:"uid"` Name string `xorm:"name" json:"name"` Type MigrateDataType `xorm:"resource_type" json:"type"` @@ -98,9 +98,10 @@ const ( type ItemStatus string const ( - ItemStatusOK ItemStatus = "OK" - ItemStatusWarning ItemStatus = "WARNING" - ItemStatusError ItemStatus = "ERROR" + // Returned by GMS + ItemStatusOK ItemStatus = "OK" + ItemStatusError ItemStatus = "ERROR" + // Used by default while awaiting GMS results ItemStatusPending ItemStatus = "PENDING" ) @@ -180,7 +181,11 @@ type UpdateSnapshotCmd struct { UID string SessionID string Status SnapshotStatus - Resources []CloudMigrationResource + + // LocalResourcesToCreate represents the local state of a resource before it has been uploaded to GMS + LocalResourcesToCreate []CloudMigrationResource + // CloudResourcesToUpdate represents resource state from GMS, to be merged with the local state + CloudResourcesToUpdate []CloudMigrationResource } // access token diff --git a/pkg/services/dashboards/dashboard_service_mock.go b/pkg/services/dashboards/dashboard_service_mock.go index 5e49ea6ee3e..8847aafde85 100644 --- a/pkg/services/dashboards/dashboard_service_mock.go +++ b/pkg/services/dashboards/dashboard_service_mock.go @@ -121,7 +121,7 @@ func (_m *FakeDashboardService) DeleteDashboard(ctx context.Context, dashboardId } // DeleteAllDashboards provides a mock function with given fields: ctx, orgID -func (_m *FakeDashboardService) DeleteAllDashboards(ctx context.Context, orgID int64) error { +func (_m *FakeDashboardService) DeleteAllDashboards(ctx context.Context, orgID int64) error { ret := _m.Called(ctx, orgID) if len(ret) == 0 { From 9e5fd78b52e62f28fb41ca28eeb9237ab8b73b1f Mon Sep 17 00:00:00 2001 From: Selene Date: Fri, 10 Jan 2025 21:43:40 +0100 Subject: [PATCH 15/19] Codegen: Remove pfs codegen dependency from Grafana codebase (#98840) * Remove pfs dependency for IAM struct to avoid to import codegen code in main go.mod * Remove pointer * Remove dependency cycle * Update tests --- go.mod | 16 ----- go.sum | 22 ------ pkg/api/dtos/plugins.go | 4 +- pkg/api/plugins.go | 16 ++--- pkg/api/plugins_test.go | 9 +-- pkg/plugins/auth/models.go | 13 +++- pkg/plugins/codegen/pfs/plugindef_types.go | 23 +------ pkg/plugins/manager/fakes/fakes.go | 3 +- pkg/plugins/plugins.go | 3 +- .../pluginsintegration/loader/loader_test.go | 9 +-- .../pluginsintegration/pipeline/steps.go | 3 +- .../pluginconfig/envvars_test.go | 3 +- .../serviceregistration.go | 14 ++-- pkg/storage/unified/apistore/go.mod | 21 +----- pkg/storage/unified/apistore/go.sum | 45 +++--------- pkg/storage/unified/resource/go.mod | 8 +-- pkg/storage/unified/resource/go.sum | 69 +++++++++++-------- 17 files changed, 90 insertions(+), 191 deletions(-) diff --git a/go.mod b/go.mod index 0d3d3b219fb..0e932edb930 100644 --- a/go.mod +++ b/go.mod @@ -470,8 +470,6 @@ require github.com/grafana/grafana/apps/alerting/notifications v0.0.0-2024120916 require github.com/grafana/grafana/apps/investigation v0.0.0-20241218083103-f46c07aba7b6 // @fcjack @matryer -require github.com/grafana/grafana/pkg/plugins/codegen v0.0.0-00010101000000-000000000000 // @grafana/grafana-as-code - require ( cel.dev/expr v0.18.0 // indirect cloud.google.com/go/longrunning v0.6.0 // indirect @@ -495,15 +493,10 @@ require ( github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cockroachdb/apd/v3 v3.2.1 // indirect - github.com/dave/dst v0.27.3 // indirect github.com/dolthub/maphash v0.1.0 // indirect - github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/gammazero/deque v0.2.1 // indirect github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect - github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d // indirect - github.com/grafana/cuetsy v0.1.11 // indirect - github.com/grafana/grafana/pkg/codegen v0.0.0-00010101000000-000000000000 // indirect github.com/grafana/jsonparser v0.0.0-20240425183733-ea80629e1a32 // indirect github.com/grafana/loki/pkg/push v0.0.0-20231124142027-e52380921608 // indirect github.com/grafana/sqlds/v4 v4.1.3 // indirect @@ -511,9 +504,7 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/serf v0.10.1 // indirect - github.com/kr/text v0.2.0 // indirect github.com/maypok86/otter v1.2.2 // indirect - github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e // indirect @@ -524,8 +515,6 @@ require ( github.com/sercand/kuberesolver/v5 v5.1.1 // indirect github.com/shadowspore/fossil-delta v0.0.0-20240102155221-e3a8590b820b // indirect github.com/sony/gobreaker v0.5.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect go.etcd.io/bbolt v1.3.11 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/featuregate v1.9.0 // indirect @@ -550,11 +539,6 @@ replace xorm.io/xorm => github.com/grafana/grafana/pkg/util/xorm v0.0.1 // lock for mysql tsdb compat replace github.com/go-sql-driver/mysql => github.com/go-sql-driver/mysql v1.7.1 -replace ( - github.com/grafana/grafana/pkg/codegen => ./pkg/codegen // @grafana/grafana-as-code - github.com/grafana/grafana/pkg/plugins/codegen => ./pkg/plugins/codegen // @grafana/grafana-as-code -) - // v1.* versions were retracted, we need to stick with v0.*. This should work // without the exclude, but this otherwise gets pulled in as a transitive // dependency. diff --git a/go.sum b/go.sum index 24a8d31267b..e9dc7a3ec43 100644 --- a/go.sum +++ b/go.sum @@ -1793,10 +1793,7 @@ github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKX github.com/dave/astrid v0.0.0-20170323122508-8c2895878b14/go.mod h1:Sth2QfxfATb/nW4EsrSi2KyJmbcniZ8TgTaji17D6ms= github.com/dave/brenda v1.1.0/go.mod h1:4wCUr6gSlu5/1Tk7akE5X7UorwiQ8Rij0SKH3/BGMOM= github.com/dave/courtney v0.3.0/go.mod h1:BAv3hA06AYfNUjfjQr+5gc6vxeBVOupLqrColj+QSD8= -github.com/dave/dst v0.27.3 h1:P1HPoMza3cMEquVf9kKy8yXsFirry4zEnWOdYPOoIzY= -github.com/dave/dst v0.27.3/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc= github.com/dave/gopackages v0.0.0-20170318123100-46e7023ec56e/go.mod h1:i00+b/gKdIDIxuLDFob7ustLAVqhsZRk2qVZrArELGQ= -github.com/dave/jennifer v1.6.0 h1:MQ/6emI2xM7wt0tJzJzyUik2Q3Tcn2eE0vtYgh4GPVI= github.com/dave/jennifer v1.6.0/go.mod h1:AxTG893FiZKqxy3FP1kL80VMshSMuz2G+EgvszgGRnk= github.com/dave/kerr v0.0.0-20170318121727-bc25dd6abe8e/go.mod h1:qZqlPyPvfsDJt+3wHJ1EvSXDuVjFTK0j2p/ca+gtsb8= github.com/dave/patsy v0.0.0-20210517141501-957256f50cba/go.mod h1:qfR88CgEGLoiqDaE+xxDCi5QA5v4vUoW0UCX2Nd5Tlc= @@ -1840,9 +1837,6 @@ github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ= github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4= -github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58= -github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w= -github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -2289,10 +2283,6 @@ github.com/grafana/authlib v0.0.0-20250107102310-3edeb9fc9d5f h1:BcgUTu26JtOudfp github.com/grafana/authlib v0.0.0-20250107102310-3edeb9fc9d5f/go.mod h1:x7df73G3xuSD35Xv9cjaMLyPJCgM9Z/Wj5ISouoAfiI= github.com/grafana/authlib/claims v0.0.0-20241202085737-df90af04f335 h1:3DHH81RJCi8Bcgn2MdBh7vgWUshmAFjZzBCVuxiQ0uk= github.com/grafana/authlib/claims v0.0.0-20241202085737-df90af04f335/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A= -github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d h1:hrXbGJ5jgp6yNITzs5o+zXq0V5yT3siNJ+uM8LGwWKk= -github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s= -github.com/grafana/cuetsy v0.1.11 h1:I3IwBhF+UaQxRM79HnImtrAn8REGdb5M3+C4QrYHoWk= -github.com/grafana/cuetsy v0.1.11/go.mod h1:Ix97+CPD8ws9oSSxR3/Lf4ahU1I4Np83kjJmDVnLZvc= github.com/grafana/dataplane/examples v0.0.1 h1:K9M5glueWyLoL4//H+EtTQq16lXuHLmOhb6DjSCahzA= github.com/grafana/dataplane/examples v0.0.1/go.mod h1:h5YwY8s407/17XF5/dS8XrUtsTVV2RnuW8+m1Mp46mg= github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6kE/MWfg7s= @@ -2654,8 +2644,6 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ= -github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU= github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM= @@ -2803,8 +2791,6 @@ github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1/go.mod h1:mpRZBD8SJ55 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 h1:ykgG34472DWey7TSjd8vIfNykXgjOgYJZoQbKfEeY/Q= -github.com/oapi-codegen/oapi-codegen/v2 v2.4.1/go.mod h1:N5+lY1tiTDV3V1BeHtOxeWXHoPVeApvsvjJqegfoaz8= github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro= github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= @@ -2817,7 +2803,6 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= @@ -2841,7 +2826,6 @@ github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xl github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= @@ -3070,7 +3054,6 @@ github.com/segmentio/encoding v0.4.0 h1:MEBYvRqiUB2nfR2criEXWqwdY6HJOUrCn5hboVOV github.com/segmentio/encoding v0.4.0/go.mod h1:/d03Cd8PoaDeceuhUUUQWjU0KhWjrmYrWPgtJHYZSnI= github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aeprPTHb6yY= github.com/sercand/kuberesolver/v5 v5.1.1/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYMWZJ294T3BtmVCpQ= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= @@ -3112,8 +3095,6 @@ github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIK github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/speakeasy-api/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= -github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= @@ -3207,8 +3188,6 @@ github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6S github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/vburenin/ifacemaker v1.2.1/go.mod h1:5WqrzX2aD7/hi+okBjcaEQJMg4lDGrpuEX3B8L4Wgrs= -github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= -github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= github.com/wk8/go-ordered-map v1.0.0 h1:BV7z+2PaK8LTSd/mWgY12HyMAo5CEgkHqbkVq2thqr8= @@ -4475,7 +4454,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/pkg/api/dtos/plugins.go b/pkg/api/dtos/plugins.go index c304372c3b0..63f3ae1a6cf 100644 --- a/pkg/api/dtos/plugins.go +++ b/pkg/api/dtos/plugins.go @@ -2,7 +2,7 @@ package dtos import ( "github.com/grafana/grafana/pkg/plugins" - "github.com/grafana/grafana/pkg/plugins/codegen/pfs" + "github.com/grafana/grafana/pkg/plugins/auth" "github.com/grafana/grafana/pkg/services/accesscontrol" ) @@ -52,7 +52,7 @@ type PluginListItem struct { SignatureOrg string `json:"signatureOrg"` AccessControl accesscontrol.Metadata `json:"accessControl,omitempty"` AngularDetected bool `json:"angularDetected"` - IAM *pfs.IAM `json:"iam,omitempty"` + IAM *auth.IAM `json:"iam,omitempty"` } type PluginList []PluginListItem diff --git a/pkg/api/plugins.go b/pkg/api/plugins.go index 2c66614ecfb..b608165a8e0 100644 --- a/pkg/api/plugins.go +++ b/pkg/api/plugins.go @@ -13,6 +13,7 @@ import ( "sort" "strings" + "github.com/grafana/grafana/pkg/plugins/auth" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -21,7 +22,6 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/plugins" - "github.com/grafana/grafana/pkg/plugins/codegen/pfs" "github.com/grafana/grafana/pkg/plugins/repo" ac "github.com/grafana/grafana/pkg/services/accesscontrol" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" @@ -74,7 +74,7 @@ func (hs *HTTPServer) GetPluginList(c *contextmodel.ReqContext) response.Respons // Filter plugins pluginDefinitions := hs.pluginStore.Plugins(c.Req.Context()) - filteredPluginDefinitions := []pluginstore.Plugin{} + filteredPluginDefinitions := make([]pluginstore.Plugin, 0) filteredPluginIDs := map[string]bool{} for _, pluginDef := range pluginDefinitions { // filter out app sub plugins @@ -583,14 +583,14 @@ func (hs *HTTPServer) hasPluginRequestedPermissions(c *contextmodel.ReqContext, } // evalAllPermissions generates an evaluator with all permissions from the input slice -func evalAllPermissions(ps []pfs.Permission) ac.Evaluator { - res := []ac.Evaluator{} - for _, p := range ps { - if p.Scope != nil { - res = append(res, ac.EvalPermission(p.Action, *p.Scope)) +func evalAllPermissions(ps []auth.Permission) ac.Evaluator { + res := make([]ac.Evaluator, len(ps)) + for i, p := range ps { + if p.Scope != "" { + res[i] = ac.EvalPermission(p.Action, p.Scope) continue } - res = append(res, ac.EvalPermission(p.Action)) + res[i] = ac.EvalPermission(p.Action) } return ac.EvalAll(res...) } diff --git a/pkg/api/plugins_test.go b/pkg/api/plugins_test.go index f251aa604fe..639dd12f174 100644 --- a/pkg/api/plugins_test.go +++ b/pkg/api/plugins_test.go @@ -13,6 +13,7 @@ import ( "testing" "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana/pkg/plugins/auth" "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" "github.com/stretchr/testify/assert" @@ -23,7 +24,6 @@ import ( "github.com/grafana/grafana/pkg/infra/log/logtest" "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/plugins" - "github.com/grafana/grafana/pkg/plugins/codegen/pfs" "github.com/grafana/grafana/pkg/plugins/config" "github.com/grafana/grafana/pkg/plugins/manager/fakes" "github.com/grafana/grafana/pkg/plugins/manager/filestore" @@ -682,14 +682,11 @@ func createPlugin(jd plugins.JSONData, class plugins.Class, files plugins.FS) *p } func TestHTTPServer_hasPluginRequestedPermissions(t *testing.T) { - newStr := func(s string) *string { - return &s - } pluginReg := pluginstore.Plugin{ JSONData: plugins.JSONData{ ID: "grafana-test-app", - IAM: &pfs.IAM{ - Permissions: []pfs.Permission{{Action: ac.ActionUsersRead, Scope: newStr(ac.ScopeUsersAll)}, {Action: ac.ActionUsersCreate}}, + IAM: &auth.IAM{ + Permissions: []auth.Permission{{Action: ac.ActionUsersRead, Scope: ac.ScopeUsersAll}, {Action: ac.ActionUsersCreate}}, }, }, } diff --git a/pkg/plugins/auth/models.go b/pkg/plugins/auth/models.go index 20fdd510ce8..16248c13839 100644 --- a/pkg/plugins/auth/models.go +++ b/pkg/plugins/auth/models.go @@ -2,8 +2,6 @@ package auth import ( "context" - - "github.com/grafana/grafana/pkg/plugins/codegen/pfs" ) type ExternalService struct { @@ -12,8 +10,17 @@ type ExternalService struct { PrivateKey string `json:"privateKey"` } +type IAM struct { + Permissions []Permission `json:"permissions,omitempty"` +} + +type Permission struct { + Action string `json:"action"` + Scope string `json:"scope"` +} + type ExternalServiceRegistry interface { HasExternalService(ctx context.Context, pluginID string) (bool, error) - RegisterExternalService(ctx context.Context, pluginID string, pType pfs.Type, svc *pfs.IAM) (*ExternalService, error) + RegisterExternalService(ctx context.Context, pluginID string, pType string, svc *IAM) (*ExternalService, error) RemoveExternalService(ctx context.Context, pluginID string) error } diff --git a/pkg/plugins/codegen/pfs/plugindef_types.go b/pkg/plugins/codegen/pfs/plugindef_types.go index 841200428a0..add148545bf 100644 --- a/pkg/plugins/codegen/pfs/plugindef_types.go +++ b/pkg/plugins/codegen/pfs/plugindef_types.go @@ -1,38 +1,17 @@ package pfs -type Type string - -// Defines values for Type. -const ( - TypeApp Type = "app" - TypeDatasource Type = "datasource" - TypePanel Type = "panel" - TypeRenderer Type = "renderer" - TypeSecretsmanager Type = "secretsmanager" -) - type PluginDef struct { Id string Name string Backend *bool - Type Type + Type string Info Info - IAM IAM } type Info struct { Version *string } -type IAM struct { - Permissions []Permission `json:"permissions,omitempty"` -} - -type Permission struct { - Action string `json:"action"` - Scope *string `json:"scope,omitempty"` -} - func (pd PluginDef) Validate() error { if pd.Id == "" || pd.Name == "" || pd.Type == "" { return ErrInvalidRootFile diff --git a/pkg/plugins/manager/fakes/fakes.go b/pkg/plugins/manager/fakes/fakes.go index ab2bb4b54f9..04623adda41 100644 --- a/pkg/plugins/manager/fakes/fakes.go +++ b/pkg/plugins/manager/fakes/fakes.go @@ -14,7 +14,6 @@ import ( "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/auth" "github.com/grafana/grafana/pkg/plugins/backendplugin" - "github.com/grafana/grafana/pkg/plugins/codegen/pfs" "github.com/grafana/grafana/pkg/plugins/log" "github.com/grafana/grafana/pkg/plugins/repo" "github.com/grafana/grafana/pkg/plugins/storage" @@ -517,7 +516,7 @@ func (f *FakeAuthService) HasExternalService(ctx context.Context, pluginID strin return f.Result != nil, nil } -func (f *FakeAuthService) RegisterExternalService(ctx context.Context, pluginID string, pType pfs.Type, svc *pfs.IAM) (*auth.ExternalService, error) { +func (f *FakeAuthService) RegisterExternalService(ctx context.Context, pluginID string, pType string, svc *auth.IAM) (*auth.ExternalService, error) { return f.Result, nil } diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index 53903715c74..08325f8fb40 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -18,7 +18,6 @@ import ( "github.com/grafana/grafana/pkg/plugins/backendplugin" "github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2" "github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin" - "github.com/grafana/grafana/pkg/plugins/codegen/pfs" "github.com/grafana/grafana/pkg/plugins/log" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/util" @@ -131,7 +130,7 @@ type JSONData struct { Executable string `json:"executable,omitempty"` // App Service Auth Registration - IAM *pfs.IAM `json:"iam,omitempty"` + IAM *auth.IAM `json:"iam,omitempty"` } func ReadPluginJSON(reader io.Reader) (JSONData, error) { diff --git a/pkg/services/pluginsintegration/loader/loader_test.go b/pkg/services/pluginsintegration/loader/loader_test.go index 053eca1d50e..9395d9b6f29 100644 --- a/pkg/services/pluginsintegration/loader/loader_test.go +++ b/pkg/services/pluginsintegration/loader/loader_test.go @@ -16,7 +16,6 @@ import ( "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/auth" "github.com/grafana/grafana/pkg/plugins/backendplugin" - "github.com/grafana/grafana/pkg/plugins/codegen/pfs" "github.com/grafana/grafana/pkg/plugins/config" "github.com/grafana/grafana/pkg/plugins/log" "github.com/grafana/grafana/pkg/plugins/manager/fakes" @@ -521,8 +520,6 @@ func TestLoader_Load(t *testing.T) { } func TestLoader_Load_ExternalRegistration(t *testing.T) { - stringPtr := func(s string) *string { return &s } - t.Run("Load a plugin with service account registration", func(t *testing.T) { cfg := &config.PluginManagementCfg{ PluginsAllowUnsigned: []string{"grafana-test-datasource"}, @@ -562,11 +559,11 @@ func TestLoader_Load_ExternalRegistration(t *testing.T) { ExposedComponents: []plugins.ExposedComponent{}, ExtensionPoints: []plugins.ExtensionPoint{}, }, - IAM: &pfs.IAM{ - Permissions: []pfs.Permission{ + IAM: &auth.IAM{ + Permissions: []auth.Permission{ { Action: "read", - Scope: stringPtr("datasource"), + Scope: "datasource", }, }, }, diff --git a/pkg/services/pluginsintegration/pipeline/steps.go b/pkg/services/pluginsintegration/pipeline/steps.go index e12cd664b31..0c82d3f07a3 100644 --- a/pkg/services/pluginsintegration/pipeline/steps.go +++ b/pkg/services/pluginsintegration/pipeline/steps.go @@ -13,7 +13,6 @@ import ( "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/auth" - "github.com/grafana/grafana/pkg/plugins/codegen/pfs" "github.com/grafana/grafana/pkg/plugins/config" "github.com/grafana/grafana/pkg/plugins/log" "github.com/grafana/grafana/pkg/plugins/manager/pipeline/initialization" @@ -57,7 +56,7 @@ func (r *ExternalServiceRegistration) Register(ctx context.Context, p *plugins.P ctxLogger := r.log.FromContext(ctx) - s, err := r.externalServiceRegistry.RegisterExternalService(ctx, p.ID, pfs.Type(p.Type), p.IAM) + s, err := r.externalServiceRegistry.RegisterExternalService(ctx, p.ID, string(p.Type), p.IAM) if err != nil { ctxLogger.Error("Could not register an external service. Initialization skipped", "pluginId", p.ID, "error", err) span.SetStatus(codes.Error, fmt.Sprintf("could not register external service: %v", err)) diff --git a/pkg/services/pluginsintegration/pluginconfig/envvars_test.go b/pkg/services/pluginsintegration/pluginconfig/envvars_test.go index b113a5bbd4c..e18809d17ad 100644 --- a/pkg/services/pluginsintegration/pluginconfig/envvars_test.go +++ b/pkg/services/pluginsintegration/pluginconfig/envvars_test.go @@ -14,7 +14,6 @@ import ( "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/auth" - "github.com/grafana/grafana/pkg/plugins/codegen/pfs" "github.com/grafana/grafana/pkg/plugins/config" "github.com/grafana/grafana/pkg/plugins/envvars" "github.com/grafana/grafana/pkg/plugins/manager/fakes" @@ -457,7 +456,7 @@ func TestPluginEnvVarsProvider_authEnvVars(t *testing.T) { p := &plugins.Plugin{ JSONData: plugins.JSONData{ ID: "test", - IAM: &pfs.IAM{}, + IAM: &auth.IAM{}, }, ExternalService: &auth.ExternalService{ ClientID: "clientID", diff --git a/pkg/services/pluginsintegration/serviceregistration/serviceregistration.go b/pkg/services/pluginsintegration/serviceregistration/serviceregistration.go index 560e00ca400..d0c89247207 100644 --- a/pkg/services/pluginsintegration/serviceregistration/serviceregistration.go +++ b/pkg/services/pluginsintegration/serviceregistration/serviceregistration.go @@ -4,8 +4,8 @@ import ( "context" "errors" + "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/auth" - "github.com/grafana/grafana/pkg/plugins/codegen/pfs" "github.com/grafana/grafana/pkg/plugins/log" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/extsvcauth" @@ -42,7 +42,7 @@ func (s *Service) HasExternalService(ctx context.Context, pluginID string) (bool } // RegisterExternalService is a simplified wrapper around SaveExternalService for the plugin use case. -func (s *Service) RegisterExternalService(ctx context.Context, pluginID string, pType pfs.Type, svc *pfs.IAM) (*auth.ExternalService, error) { +func (s *Service) RegisterExternalService(ctx context.Context, pluginID string, pType string, svc *auth.IAM) (*auth.ExternalService, error) { ctxLogger := s.log.FromContext(ctx) if !s.featureEnabled { @@ -53,7 +53,7 @@ func (s *Service) RegisterExternalService(ctx context.Context, pluginID string, // Datasource plugins can only be enabled enabled := true // App plugins can be disabled - if pType == pfs.TypeApp { + if pType == string(plugins.TypeApp) { settings, err := s.settingsSvc.GetPluginSettingByPluginID(ctx, &pluginsettings.GetByPluginIDArgs{PluginID: pluginID}) if err != nil && !errors.Is(err, pluginsettings.ErrPluginSettingNotFound) { return nil, err @@ -89,16 +89,12 @@ func (s *Service) RegisterExternalService(ctx context.Context, pluginID string, PrivateKey: privateKey}, nil } -func toAccessControlPermissions(ps []pfs.Permission) []accesscontrol.Permission { +func toAccessControlPermissions(ps []auth.Permission) []accesscontrol.Permission { res := make([]accesscontrol.Permission, 0, len(ps)) for _, p := range ps { - scope := "" - if p.Scope != nil { - scope = *p.Scope - } res = append(res, accesscontrol.Permission{ Action: p.Action, - Scope: scope, + Scope: p.Scope, }) } return res diff --git a/pkg/storage/unified/apistore/go.mod b/pkg/storage/unified/apistore/go.mod index e0b1c873a0a..c36cb745f2e 100644 --- a/pkg/storage/unified/apistore/go.mod +++ b/pkg/storage/unified/apistore/go.mod @@ -37,8 +37,6 @@ require ( cloud.google.com/go/compute/metadata v0.5.2 // indirect cloud.google.com/go/iam v1.2.0 // indirect cloud.google.com/go/storage v1.43.0 // indirect - cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e // indirect - cuelang.org/go v0.8.2 // indirect dario.cat/mergo v1.0.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 // indirect @@ -111,11 +109,9 @@ require ( github.com/cheekybits/genny v1.0.0 // indirect github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476 // indirect github.com/cloudflare/circl v1.3.7 // indirect - github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect - github.com/dave/dst v0.27.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect github.com/dlmiddlecote/sqlstats v1.0.2 // indirect @@ -123,7 +119,6 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/elazarl/goproxy v1.2.6 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/emicklei/proto v1.13.2 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect github.com/fatih/color v1.17.0 // indirect @@ -176,8 +171,6 @@ require ( github.com/gorilla/mux v1.8.1 // indirect github.com/grafana/alerting v0.0.0-20241211182001-0f317eb6b2f7 // indirect github.com/grafana/authlib v0.0.0-20250107102310-3edeb9fc9d5f // indirect - github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d // indirect - github.com/grafana/cuetsy v0.1.11 // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect github.com/grafana/dskit v0.0.0-20241105154643-a6b453a88040 // indirect github.com/grafana/grafana-aws-sdk v0.31.5 // indirect @@ -223,7 +216,6 @@ require ( github.com/karlseguin/ccache/v3 v3.0.5 // indirect github.com/klauspost/compress v1.17.11 // indirect github.com/klauspost/cpuid/v2 v2.2.9 // indirect - github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect @@ -241,7 +233,6 @@ require ( github.com/miekg/dns v1.1.61 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/mithrandie/csvq v1.18.1 // indirect @@ -257,20 +248,17 @@ require ( github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/natefinch/wrap v0.2.0 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect - github.com/oapi-codegen/oapi-codegen/v2 v2.3.0 // indirect github.com/oklog/run v1.1.0 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/oklog/ulid/v2 v2.1.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0 // indirect github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 // indirect github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f // indirect github.com/openfga/openfga v1.6.2 // indirect github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect @@ -284,10 +272,8 @@ require ( github.com/prometheus/common/sigv4 v0.1.0 // indirect github.com/prometheus/exporter-toolkit v0.11.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/protocolbuffers/txtpbfmt v0.0.0-20240116145035-ef3ab179eed6 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/rs/cors v1.11.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect @@ -314,7 +300,6 @@ require ( github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a // indirect github.com/urfave/cli v1.22.16 // indirect github.com/x448/float16 v0.8.4 // indirect - github.com/xlab/treeprint v1.2.0 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect go.etcd.io/bbolt v1.3.11 // indirect go.etcd.io/etcd/api/v3 v3.5.16 // indirect @@ -342,14 +327,14 @@ require ( go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.32.0 // indirect golang.org/x/mod v0.22.0 // indirect - golang.org/x/net v0.33.0 // indirect + golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.29.0 // indirect golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.7.0 // indirect - golang.org/x/tools v0.28.0 // indirect + golang.org/x/tools v0.29.0 // indirect golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect gonum.org/v1/gonum v0.15.1 // indirect google.golang.org/api v0.193.0 // indirect diff --git a/pkg/storage/unified/apistore/go.sum b/pkg/storage/unified/apistore/go.sum index 0e96811149d..a92d7bc43c6 100644 --- a/pkg/storage/unified/apistore/go.sum +++ b/pkg/storage/unified/apistore/go.sum @@ -47,10 +47,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= -cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e h1:GwCVItFUPxwdsEYnlUcJ6PJxOjTeFFCKOh6QWg4oAzQ= -cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e/go.mod h1:ApHceQLLwcOkCEXM1+DyCXTHEJhNGDpJ2kmV6axsx24= -cuelang.org/go v0.8.2 h1:vWfHI1kQlBvwkna7ktAqXjV5LUEAgU6vyMlJjvZZaDw= -cuelang.org/go v0.8.2/go.mod h1:CoDbYolfMms4BhWUlhD+t5ORnihR7wvjcfgyO9lL5FI= +cuelang.org/go v0.11.1 h1:pV+49MX1mmvDm8Qh3Za3M786cty8VKPWzQ1Ho4gZRP0= +cuelang.org/go v0.11.1/go.mod h1:PBY6XvPUswPPJ2inpvUozP9mebDVTXaeehQikhZPBz0= dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= @@ -255,6 +253,7 @@ github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vc github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= @@ -268,7 +267,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg= github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc= @@ -279,10 +277,6 @@ github.com/cznic/ql v1.2.0/go.mod h1:FbpzhyZrqr0PVlK6ury+PoW3T0ODUV22OeWIxcaOrSE github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8= -github.com/dave/dst v0.27.3 h1:P1HPoMza3cMEquVf9kKy8yXsFirry4zEnWOdYPOoIzY= -github.com/dave/dst v0.27.3/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc= -github.com/dave/jennifer v1.6.0 h1:MQ/6emI2xM7wt0tJzJzyUik2Q3Tcn2eE0vtYgh4GPVI= -github.com/dave/jennifer v1.6.0/go.mod h1:AxTG893FiZKqxy3FP1kL80VMshSMuz2G+EgvszgGRnk= 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= @@ -318,8 +312,6 @@ github.com/elazarl/goproxy v1.2.6 h1:jk1cwYYz96HhB985lQ1FFv7UcYVQHV84w8lWtpxW7WE github.com/elazarl/goproxy v1.2.6/go.mod h1:yBhqz1/IaNA5tCayHGVfFmuzyanF6YeDNGIwPhfvtp8= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY= -github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -393,8 +385,6 @@ github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+Gr github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= -github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= -github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -553,10 +543,6 @@ github.com/grafana/authlib v0.0.0-20250107102310-3edeb9fc9d5f h1:BcgUTu26JtOudfp github.com/grafana/authlib v0.0.0-20250107102310-3edeb9fc9d5f/go.mod h1:x7df73G3xuSD35Xv9cjaMLyPJCgM9Z/Wj5ISouoAfiI= github.com/grafana/authlib/claims v0.0.0-20241202085737-df90af04f335 h1:3DHH81RJCi8Bcgn2MdBh7vgWUshmAFjZzBCVuxiQ0uk= github.com/grafana/authlib/claims v0.0.0-20241202085737-df90af04f335/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A= -github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d h1:hrXbGJ5jgp6yNITzs5o+zXq0V5yT3siNJ+uM8LGwWKk= -github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s= -github.com/grafana/cuetsy v0.1.11 h1:I3IwBhF+UaQxRM79HnImtrAn8REGdb5M3+C4QrYHoWk= -github.com/grafana/cuetsy v0.1.11/go.mod h1:Ix97+CPD8ws9oSSxR3/Lf4ahU1I4Np83kjJmDVnLZvc= github.com/grafana/dataplane/examples v0.0.1 h1:K9M5glueWyLoL4//H+EtTQq16lXuHLmOhb6DjSCahzA= github.com/grafana/dataplane/examples v0.0.1/go.mod h1:h5YwY8s407/17XF5/dS8XrUtsTVV2RnuW8+m1Mp46mg= github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6kE/MWfg7s= @@ -729,8 +715,6 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ= -github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM= github.com/mattetti/filebuffer v1.0.1/go.mod h1:YdMURNDOttIiruleeVr6f56OrMc+MydEnTcXwtkxNVs= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -765,8 +749,6 @@ github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa1 github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= -github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c h1:cqn374mizHuIWj+OSJCajGr/phAmuMug9qIX3l9CflE= github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= @@ -805,8 +787,6 @@ github.com/natefinch/wrap v0.2.0 h1:IXzc/pw5KqxJv55gV0lSOcKHYuEZPGbQrOOXr/bamRk= github.com/natefinch/wrap v0.2.0/go.mod h1:6gMHlAl12DwYEfKP3TkuykYUfLSEAvHw67itm4/KAS8= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/oapi-codegen/oapi-codegen/v2 v2.3.0 h1:rICjNsHbPP1LttefanBPnwsSwl09SqhCO7Ee623qR84= -github.com/oapi-codegen/oapi-codegen/v2 v2.3.0/go.mod h1:4k+cJeSq5ntkwlcpQSxLxICCxQzCL772o30PxdibRt4= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= @@ -847,8 +827,8 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= -github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -908,8 +888,6 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/protocolbuffers/txtpbfmt v0.0.0-20240116145035-ef3ab179eed6 h1:MAzmm+JtFxQwTPb1cVMLkemw2OxLy5AB/d/rxtAwGQQ= -github.com/protocolbuffers/txtpbfmt v0.0.0-20240116145035-ef3ab179eed6/go.mod h1:jgxiZysxFPM+iWKwQwPR+y+Jvo54ARd4EisXxKYpB5c= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= @@ -931,8 +909,6 @@ github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWR github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -1024,8 +1000,6 @@ github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhe github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk= github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= -github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1216,8 +1190,8 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1395,8 +1369,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= -golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= +golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= 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= @@ -1539,7 +1513,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/storage/unified/resource/go.mod b/pkg/storage/unified/resource/go.mod index 976f9322d7c..f12ce1cef38 100644 --- a/pkg/storage/unified/resource/go.mod +++ b/pkg/storage/unified/resource/go.mod @@ -37,7 +37,6 @@ require ( cloud.google.com/go/compute/metadata v0.5.2 // indirect cloud.google.com/go/iam v1.2.0 // indirect cloud.google.com/go/storage v1.43.0 // indirect - cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 // indirect @@ -47,6 +46,7 @@ require ( github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/BurntSushi/toml v1.4.0 // indirect + github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // indirect github.com/apache/arrow-go/v18 v18.0.1-0.20241212180703-82be143d7c30 // indirect github.com/armon/go-metrics v0.4.1 // indirect @@ -78,7 +78,6 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cheekybits/genny v1.0.0 // indirect github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476 // indirect - github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -174,7 +173,6 @@ require ( github.com/oklog/run v1.1.0 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect @@ -219,13 +217,13 @@ require ( golang.org/x/crypto v0.32.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/mod v0.22.0 // indirect - golang.org/x/net v0.33.0 // indirect + golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sys v0.29.0 // indirect golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.7.0 // indirect - golang.org/x/tools v0.28.0 // indirect + golang.org/x/tools v0.29.0 // indirect golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect google.golang.org/api v0.193.0 // indirect google.golang.org/genproto v0.0.0-20240820151423-278611b39280 // indirect diff --git a/pkg/storage/unified/resource/go.sum b/pkg/storage/unified/resource/go.sum index b27cb9905cf..4a906de16a2 100644 --- a/pkg/storage/unified/resource/go.sum +++ b/pkg/storage/unified/resource/go.sum @@ -15,12 +15,11 @@ cloud.google.com/go/longrunning v0.6.0 h1:mM1ZmaNsQsnb+5n1DNPeL0KwQd9jQRqSqSDEkB cloud.google.com/go/longrunning v0.6.0/go.mod h1:uHzSZqW89h7/pasCWNYdUpwGz3PcVWhrWupreVPYLts= cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= -cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e h1:GwCVItFUPxwdsEYnlUcJ6PJxOjTeFFCKOh6QWg4oAzQ= -cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e/go.mod h1:ApHceQLLwcOkCEXM1+DyCXTHEJhNGDpJ2kmV6axsx24= -cuelang.org/go v0.8.2 h1:vWfHI1kQlBvwkna7ktAqXjV5LUEAgU6vyMlJjvZZaDw= -cuelang.org/go v0.8.2/go.mod h1:CoDbYolfMms4BhWUlhD+t5ORnihR7wvjcfgyO9lL5FI= +cuelang.org/go v0.11.1 h1:pV+49MX1mmvDm8Qh3Za3M786cty8VKPWzQ1Ho4gZRP0= +cuelang.org/go v0.11.1/go.mod h1:PBY6XvPUswPPJ2inpvUozP9mebDVTXaeehQikhZPBz0= dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= @@ -46,6 +45,7 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= @@ -67,6 +67,7 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f h1:HR5nRmUQgXrwqZOwZ2DAc/aCi3Bu3xENpspW935vxu0= github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f/go.mod h1:f3HiCrHjHBdcm6E83vGaXh1KomZMA2P6aeo3hKx/wg0= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -161,6 +162,7 @@ github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vc github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= @@ -172,6 +174,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg= github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc= @@ -182,8 +185,6 @@ github.com/cznic/ql v1.2.0/go.mod h1:FbpzhyZrqr0PVlK6ury+PoW3T0ODUV22OeWIxcaOrSE github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8= -github.com/dave/dst v0.27.3 h1:P1HPoMza3cMEquVf9kKy8yXsFirry4zEnWOdYPOoIzY= -github.com/dave/dst v0.27.3/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc= 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= @@ -213,8 +214,6 @@ github.com/elazarl/goproxy v1.2.6 h1:jk1cwYYz96HhB985lQ1FFv7UcYVQHV84w8lWtpxW7WE github.com/elazarl/goproxy v1.2.6/go.mod h1:yBhqz1/IaNA5tCayHGVfFmuzyanF6YeDNGIwPhfvtp8= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY= -github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -229,6 +228,7 @@ github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= @@ -243,6 +243,7 @@ github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLb github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -318,6 +319,7 @@ github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17w github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-migrate/migrate/v4 v4.7.0 h1:gONcHxHApDTKXDyLH/H97gEHmpu1zcnnbAaq2zgrPrs= github.com/golang-migrate/migrate/v4 v4.7.0/go.mod h1:Qvut3N4xKWjoH3sokBccML6WyHSnggXm/DvMMnTsQIc= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -359,6 +361,7 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -405,10 +408,6 @@ github.com/grafana/authlib v0.0.0-20250107102310-3edeb9fc9d5f h1:BcgUTu26JtOudfp github.com/grafana/authlib v0.0.0-20250107102310-3edeb9fc9d5f/go.mod h1:x7df73G3xuSD35Xv9cjaMLyPJCgM9Z/Wj5ISouoAfiI= github.com/grafana/authlib/claims v0.0.0-20241202085737-df90af04f335 h1:3DHH81RJCi8Bcgn2MdBh7vgWUshmAFjZzBCVuxiQ0uk= github.com/grafana/authlib/claims v0.0.0-20241202085737-df90af04f335/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A= -github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d h1:hrXbGJ5jgp6yNITzs5o+zXq0V5yT3siNJ+uM8LGwWKk= -github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s= -github.com/grafana/cuetsy v0.1.11 h1:I3IwBhF+UaQxRM79HnImtrAn8REGdb5M3+C4QrYHoWk= -github.com/grafana/cuetsy v0.1.11/go.mod h1:Ix97+CPD8ws9oSSxR3/Lf4ahU1I4Np83kjJmDVnLZvc= github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6kE/MWfg7s= github.com/grafana/dataplane/sdata v0.0.9/go.mod h1:Jvs5ddpGmn6vcxT7tCTWAZ1mgi4sbcdFt9utQx5uMAU= github.com/grafana/dskit v0.0.0-20241105154643-a6b453a88040 h1:IR+UNYHqaU31t8/TArJk8K/GlDwOyxMpGNkWCXeZ28g= @@ -514,10 +513,10 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 h1:SwcnSwBR7X/5EHJQlXBockkJVIMRVt5yKaesBPMtyZQ= github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6/go.mod h1:WrYiIuiXUMIvTDAQw97C+9l0CnBmCcvosPjN3XDqS/o= +github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/karlseguin/ccache/v3 v3.0.5 h1:hFX25+fxzNjsRlREYsoGNa2LoVEw5mPF8wkWq/UnevQ= github.com/karlseguin/ccache/v3 v3.0.5/go.mod h1:qxC372+Qn+IBj8Pe3KvGjHPj0sWwEF7AeZVhsNPZ6uY= @@ -589,8 +588,6 @@ github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa1 github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= -github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c h1:cqn374mizHuIWj+OSJCajGr/phAmuMug9qIX3l9CflE= github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= @@ -623,8 +620,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/oapi-codegen/oapi-codegen/v2 v2.3.0 h1:rICjNsHbPP1LttefanBPnwsSwl09SqhCO7Ee623qR84= -github.com/oapi-codegen/oapi-codegen/v2 v2.3.0/go.mod h1:4k+cJeSq5ntkwlcpQSxLxICCxQzCL772o30PxdibRt4= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= @@ -637,11 +633,7 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 h1:pAYrdyIKxPsMs/nRcTEnS9za2io11g7Rt7ng7HK82hk= github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66/go.mod h1:gil5LBD8tSdFQbUkCQdnXsoeU9kDJdJgbGdHkgJfcd0= github.com/openfga/openfga v1.6.2 h1:tHBAgiCPomCZb3IH0CFqOpTDVDA/Xb8kG87oX4JCbXc= @@ -700,8 +692,6 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/protocolbuffers/txtpbfmt v0.0.0-20240116145035-ef3ab179eed6 h1:MAzmm+JtFxQwTPb1cVMLkemw2OxLy5AB/d/rxtAwGQQ= -github.com/protocolbuffers/txtpbfmt v0.0.0-20240116145035-ef3ab179eed6/go.mod h1:jgxiZysxFPM+iWKwQwPR+y+Jvo54ARd4EisXxKYpB5c= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= @@ -785,8 +775,6 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= -github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= -github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -852,6 +840,7 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= 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= @@ -861,13 +850,23 @@ golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1m golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 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/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -901,8 +900,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -929,6 +928,7 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -984,9 +984,11 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -994,6 +996,7 @@ golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 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= @@ -1001,16 +1004,20 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= -golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= +golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= 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= golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk= golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0= gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -1064,6 +1071,7 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -1119,6 +1127,7 @@ modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk= From d73bb12b9954e2a869cab65115ed8b0c2ce43b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ida=20=C5=A0tambuk?= Date: Fri, 10 Jan 2025 23:23:23 +0100 Subject: [PATCH 16/19] Features: Remove cloudwatchMetricInsightsCrossAccount feature toggle (#98826) --- .../aws-cloudwatch/query-editor/index.md | 1 - .../feature-toggles/index.md | 1 - .../src/types/featureToggles.gen.ts | 1 - pkg/services/featuremgmt/registry.go | 8 ----- pkg/services/featuremgmt/toggles_gen.csv | 1 - pkg/services/featuremgmt/toggles_gen.go | 4 --- pkg/services/featuremgmt/toggles_gen.json | 1 + .../SQLBuilderEditor/SQLBuilderSelectRow.tsx | 35 ++++++++----------- .../SQLBuilderEditor/SQLFilter.tsx | 10 ++---- .../SQLBuilderEditor/SQLGroupBy.test.tsx | 15 +------- .../SQLBuilderEditor/SQLGroupBy.tsx | 4 +-- .../QueryEditor/QueryEditor.test.tsx | 9 ----- .../components/QueryEditor/QueryHeader.tsx | 12 ++----- 13 files changed, 21 insertions(+), 81 deletions(-) diff --git a/docs/sources/datasources/aws-cloudwatch/query-editor/index.md b/docs/sources/datasources/aws-cloudwatch/query-editor/index.md index fe44e0d7542..b65bd308e77 100644 --- a/docs/sources/datasources/aws-cloudwatch/query-editor/index.md +++ b/docs/sources/datasources/aws-cloudwatch/query-editor/index.md @@ -274,7 +274,6 @@ To enable cross-account observability, complete the following steps: Cross-account querying is available in the plugin through the **Logs**, **Metric search**, and **Metric Insights** modes. After you have it configured, you'll see a **Monitoring account** badge in the query editor header. -To support cross-account query building in the **Metric Insight** builder mode, the `cloudwatchMetricInsightsCrossAccount` feature toggle should be enabled. {{< figure src="/static/img/docs/cloudwatch/cloudwatch-monitoring-badge-9.3.0.png" max-width="1200px" caption="Monitoring account badge" >}} diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md index 09b70ac31e6..d7f0588df06 100644 --- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md +++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md @@ -75,7 +75,6 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general- | `openSearchBackendFlowEnabled` | Enables the backend query flow for Open Search datasource plugin | Yes | | `alertingApiServer` | Register Alerting APIs with the K8s API server | Yes | | `cloudWatchRoundUpEndTime` | Round up end time for metric queries to the next minute to avoid missing data | Yes | -| `cloudwatchMetricInsightsCrossAccount` | Enables cross account observability for Cloudwatch Metric Insights query builder | Yes | | `newFiltersUI` | Enables new combobox style UI for the Ad hoc filters variable in scenes architecture | Yes | | `useSessionStorageForRedirection` | Use session storage for handling the redirection after login | Yes | | `userStorageAPI` | Enables the user storage API | Yes | diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index f1d6f6a6792..8625b8880c8 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -199,7 +199,6 @@ export interface FeatureToggles { enableScopesInMetricsExplore?: boolean; alertingApiServer?: boolean; cloudWatchRoundUpEndTime?: boolean; - cloudwatchMetricInsightsCrossAccount?: boolean; prometheusAzureOverrideAudience?: boolean; alertingFilterV2?: boolean; dataplaneAggregator?: boolean; diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index 2776923bbe7..81a96f9da58 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -1375,14 +1375,6 @@ var ( Owner: awsDatasourcesSquad, Expression: "true", }, - { - Name: "cloudwatchMetricInsightsCrossAccount", - Description: "Enables cross account observability for Cloudwatch Metric Insights query builder", - Stage: FeatureStageGeneralAvailability, - Owner: awsDatasourcesSquad, - FrontendOnly: true, - Expression: "true", - }, { Name: "prometheusAzureOverrideAudience", Description: "Deprecated. Allow override default AAD audience for Azure Prometheus endpoint. Enabled by default. This feature should no longer be used and will be removed in the future.", diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index 920edee152f..7f182d4b200 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -180,7 +180,6 @@ reloadDashboardsOnParamsChange,experimental,@grafana/dashboards-squad,false,fals enableScopesInMetricsExplore,experimental,@grafana/dashboards-squad,false,false,false alertingApiServer,GA,@grafana/alerting-squad,false,true,false cloudWatchRoundUpEndTime,GA,@grafana/aws-datasources,false,false,false -cloudwatchMetricInsightsCrossAccount,GA,@grafana/aws-datasources,false,false,true prometheusAzureOverrideAudience,deprecated,@grafana/partner-datasources,false,false,false alertingFilterV2,experimental,@grafana/alerting-squad,false,false,false dataplaneAggregator,experimental,@grafana/grafana-app-platform-squad,false,true,false diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 15615506aca..b3aa97588cf 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -731,10 +731,6 @@ const ( // Round up end time for metric queries to the next minute to avoid missing data FlagCloudWatchRoundUpEndTime = "cloudWatchRoundUpEndTime" - // FlagCloudwatchMetricInsightsCrossAccount - // Enables cross account observability for Cloudwatch Metric Insights query builder - FlagCloudwatchMetricInsightsCrossAccount = "cloudwatchMetricInsightsCrossAccount" - // FlagPrometheusAzureOverrideAudience // Deprecated. Allow override default AAD audience for Azure Prometheus endpoint. Enabled by default. This feature should no longer be used and will be removed in the future. FlagPrometheusAzureOverrideAudience = "prometheusAzureOverrideAudience" diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index 36b6452c5ea..5ae300fe69b 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -869,6 +869,7 @@ "name": "cloudwatchMetricInsightsCrossAccount", "resourceVersion": "1729265619643", "creationTimestamp": "2024-07-02T10:34:12Z", + "deletionTimestamp": "2025-01-10T15:06:19Z", "annotations": { "grafana.app/updatedTimestamp": "2024-10-18 15:33:39.643165 +0000 UTC" } diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderSelectRow.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderSelectRow.tsx index d350e18bf66..dc7b6f8d7cf 100644 --- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderSelectRow.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderSelectRow.tsx @@ -53,10 +53,7 @@ const SQLBuilderSelectRow = ({ datasource, query, onQueryChange }: SQLBuilderSel const metricOptions = useMetrics(datasource, { region: query.region, namespace, - ...(config.featureToggles.cloudWatchCrossAccountQuerying && - config.featureToggles.cloudwatchMetricInsightsCrossAccount - ? { accountId: query.accountId } - : {}), + ...(config.featureToggles.cloudWatchCrossAccountQuerying && { accountId: query.accountId }), }); const existingFilters = useMemo(() => stringArrayToDimensions(schemaLabels ?? []), [schemaLabels]); const unusedDimensionKeys = useDimensionKeys(datasource, { @@ -64,10 +61,7 @@ const SQLBuilderSelectRow = ({ datasource, query, onQueryChange }: SQLBuilderSel namespace, metricName, dimensionFilters: existingFilters, - ...(config.featureToggles.cloudWatchCrossAccountQuerying && - config.featureToggles.cloudwatchMetricInsightsCrossAccount - ? { accountId: query.accountId } - : {}), + ...(config.featureToggles.cloudWatchCrossAccountQuerying && { accountId: query.accountId }), }); const dimensionKeys = useMemo( () => (schemaLabels?.length ? [...unusedDimensionKeys, ...schemaLabels.map(toOption)] : unusedDimensionKeys), @@ -93,19 +87,18 @@ const SQLBuilderSelectRow = ({ datasource, query, onQueryChange }: SQLBuilderSel return ( <> - {config.featureToggles.cloudWatchCrossAccountQuerying && - config.featureToggles.cloudwatchMetricInsightsCrossAccount && ( - { - onQueryChange({ - ...query, - accountId, - }); - }} - /> - )} + {config.featureToggles.cloudWatchCrossAccountQuerying && ( + { + onQueryChange({ + ...query, + accountId, + }); + }} + /> + )}