@grafana/plugin-ui 0.14.0-dev.1 → 0.14.1-dsconfig.bccd84e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/cjs/index.cjs +2930 -377
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/cjs/index.d.cts +358 -38
  4. package/dist/esm/components/ConfigEditor/ConfigSection/ConfigDescriptionLink.js +2 -2
  5. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/AuthorizationHeaderField.js +53 -0
  6. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/AuthorizationHeaderField.js.map +1 -0
  7. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/ComplexFieldNote.js +24 -0
  8. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/ComplexFieldNote.js.map +1 -0
  9. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/DatasourceConfigWizard.js +229 -0
  10. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/DatasourceConfigWizard.js.map +1 -0
  11. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/IndexedPairEditor.js +124 -0
  12. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/IndexedPairEditor.js.map +1 -0
  13. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/PdcFieldNote.js +34 -0
  14. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/PdcFieldNote.js.map +1 -0
  15. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/SchemaField.js +60 -0
  16. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/SchemaField.js.map +1 -0
  17. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/SecureFieldInput.js +61 -0
  18. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/SecureFieldInput.js.map +1 -0
  19. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/SidebarNav.js +54 -0
  20. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/SidebarNav.js.map +1 -0
  21. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/StringArrayInput.js +84 -0
  22. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/StringArrayInput.js.map +1 -0
  23. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/TabLayout.js +176 -0
  24. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/TabLayout.js.map +1 -0
  25. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/fieldUtils.js +88 -0
  26. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/fieldUtils.js.map +1 -0
  27. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/renderFieldInput.js +106 -0
  28. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/renderFieldInput.js.map +1 -0
  29. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/tabStyles.js +241 -0
  30. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/tabStyles.js.map +1 -0
  31. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/useDatasourceConfigForm.js +284 -0
  32. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/useDatasourceConfigForm.js.map +1 -0
  33. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/wizardStyles.js +124 -0
  34. package/dist/esm/components/ConfigEditor/DatasourceConfigWizard/wizardStyles.js.map +1 -0
  35. package/dist/esm/components/DataLinks/DataLink.js +2 -2
  36. package/dist/esm/components/DataLinks/DataLinks.js +2 -2
  37. package/dist/esm/components/DatePicker/styles.js +2 -2
  38. package/dist/esm/components/DatePickerWithInput/styles.js +2 -2
  39. package/dist/esm/components/QueryEditor/EditorField.js +2 -2
  40. package/dist/esm/components/QueryEditor/EditorHeader.js +2 -2
  41. package/dist/esm/components/QueryEditor/EditorRow.js +2 -2
  42. package/dist/esm/components/QueryEditor/EditorSwitch.js +2 -2
  43. package/dist/esm/components/QueryEditor/InlineSelect.js +1 -1
  44. package/dist/esm/components/QueryEditor/InlineSelect.js.map +1 -1
  45. package/dist/esm/components/QueryEditor/InputGroup.js +2 -2
  46. package/dist/esm/components/QueryEditor/QueryEditor.js +3 -1
  47. package/dist/esm/components/QueryEditor/QueryEditor.js.map +1 -1
  48. package/dist/esm/components/QueryEditor/QueryHeader.js +2 -2
  49. package/dist/esm/components/QueryEditor/QueryHeader.js.map +1 -1
  50. package/dist/esm/components/QueryEditor/Space.js +2 -2
  51. package/dist/esm/components/QueryEditor/TableSelector.js +0 -1
  52. package/dist/esm/components/QueryEditor/TableSelector.js.map +1 -1
  53. package/dist/esm/components/QueryEditor/defaults.js.map +1 -1
  54. package/dist/esm/components/QueryEditor/query-editor-raw/QueryEditorRaw.js +10 -2
  55. package/dist/esm/components/QueryEditor/query-editor-raw/QueryEditorRaw.js.map +1 -1
  56. package/dist/esm/components/QueryEditor/query-editor-raw/QueryToolbox.js +6 -1
  57. package/dist/esm/components/QueryEditor/query-editor-raw/QueryToolbox.js.map +1 -1
  58. package/dist/esm/components/QueryEditor/query-editor-raw/RawEditor.js +13 -3
  59. package/dist/esm/components/QueryEditor/query-editor-raw/RawEditor.js.map +1 -1
  60. package/dist/esm/components/QueryEditor/types.js +0 -1
  61. package/dist/esm/components/QueryEditor/types.js.map +1 -1
  62. package/dist/esm/components/QueryEditor/utils/formatSQL.js +15 -4
  63. package/dist/esm/components/QueryEditor/utils/formatSQL.js.map +1 -1
  64. package/dist/esm/components/QueryEditor/visual-query-builder/EditorField.js +2 -2
  65. package/dist/esm/components/QueryEditor/visual-query-builder/EditorRow.js +2 -2
  66. package/dist/esm/components/QueryEditor/visual-query-builder/Preview.js +4 -4
  67. package/dist/esm/components/QueryEditor/visual-query-builder/Preview.js.map +1 -1
  68. package/dist/esm/components/QueryEditor/visual-query-builder/SQLGroupByRow.js +0 -1
  69. package/dist/esm/components/QueryEditor/visual-query-builder/SQLGroupByRow.js.map +1 -1
  70. package/dist/esm/components/QueryEditor/visual-query-builder/SQLOrderByRow.js +0 -1
  71. package/dist/esm/components/QueryEditor/visual-query-builder/SQLOrderByRow.js.map +1 -1
  72. package/dist/esm/components/QueryEditor/visual-query-builder/SQLSelectRow.js +0 -1
  73. package/dist/esm/components/QueryEditor/visual-query-builder/SQLSelectRow.js.map +1 -1
  74. package/dist/esm/components/QueryEditor/visual-query-builder/SQLWhereRow.js +0 -1
  75. package/dist/esm/components/QueryEditor/visual-query-builder/SQLWhereRow.js.map +1 -1
  76. package/dist/esm/components/QueryEditor/visual-query-builder/SelectRow.js +2 -2
  77. package/dist/esm/components/QueryEditor/visual-query-builder/VisualEditor.js +10 -2
  78. package/dist/esm/components/QueryEditor/visual-query-builder/VisualEditor.js.map +1 -1
  79. package/dist/esm/components/SQLEditor/components/SQLEditor.js.map +1 -1
  80. package/dist/esm/components/SQLEditor/standardSql/definition.js +0 -6
  81. package/dist/esm/components/SQLEditor/standardSql/definition.js.map +1 -1
  82. package/dist/esm/components/SQLEditor/standardSql/getStatementPosition.js +2 -1
  83. package/dist/esm/components/SQLEditor/standardSql/getStatementPosition.js.map +1 -1
  84. package/dist/esm/components/SQLEditor/standardSql/statementPositionResolversRegistry.js +2 -1
  85. package/dist/esm/components/SQLEditor/standardSql/statementPositionResolversRegistry.js.map +1 -1
  86. package/dist/esm/components/SQLEditor/types.js +1 -17
  87. package/dist/esm/components/SQLEditor/types.js.map +1 -1
  88. package/dist/esm/components/SQLEditor/utils/LinkedToken.js +1 -1
  89. package/dist/esm/components/SQLEditor/utils/LinkedToken.js.map +1 -1
  90. package/dist/esm/components/SQLEditor/utils/linkedTokenBuilder.js +2 -2
  91. package/dist/esm/components/SQLEditor/utils/tokenType.js +18 -0
  92. package/dist/esm/components/SQLEditor/utils/tokenType.js.map +1 -0
  93. package/dist/esm/components/SQLEditor/utils/tokenUtils.js +1 -1
  94. package/dist/esm/components/VisualQueryBuilder/components/OperationEditorBody.js +1 -1
  95. package/dist/esm/components/VisualQueryBuilder/components/OperationList.js +1 -1
  96. package/dist/esm/components/VisualQueryBuilder/components/OperationParamEditor.js +1 -1
  97. package/dist/esm/components/VisualQueryBuilder/components/OperationsEditorRow.js +1 -1
  98. package/dist/esm/components/VisualQueryBuilder/components/QueryHeaderSwitch.js +1 -1
  99. package/dist/esm/components/VisualQueryBuilder/components/QueryOptionGroup.js +1 -1
  100. package/dist/esm/datasource/schema/config.js +235 -0
  101. package/dist/esm/datasource/schema/config.js.map +1 -0
  102. package/dist/esm/datasource/schema/datasource.js +228 -0
  103. package/dist/esm/datasource/schema/datasource.js.map +1 -0
  104. package/dist/esm/datasource/schema/llmHints.js +54 -0
  105. package/dist/esm/datasource/schema/llmHints.js.map +1 -0
  106. package/dist/esm/datasource/schema/provisioningYaml.js +356 -0
  107. package/dist/esm/datasource/schema/provisioningYaml.js.map +1 -0
  108. package/dist/esm/index.d.ts +358 -38
  109. package/dist/esm/index.js +7 -1
  110. package/dist/esm/index.js.map +1 -1
  111. package/package.json +30 -11
@@ -11,23 +11,25 @@ var e2eSelectors = require('@grafana/e2e-selectors');
11
11
  var runtime = require('@grafana/runtime');
12
12
  var reactUse = require('react-use');
13
13
  var ui$1 = require('@react-awesome-query-builder/ui');
14
- var lodash = require('lodash');
15
14
  var uuid = require('uuid');
15
+ var lodash = require('lodash');
16
16
  var AutoSizer = require('react-virtualized-auto-sizer');
17
- var sqlFormatter = require('sql-formatter-plus');
17
+ var sqlFormatter = require('sql-formatter');
18
18
  var rxjs = require('rxjs');
19
19
  var operators$1 = require('rxjs/operators');
20
+ var reactHookForm = require('react-hook-form');
20
21
  var dnd = require('@hello-pangea/dnd');
21
22
  var reactPopperTooltip = require('react-popper-tooltip');
22
23
  var Prism = require('prismjs');
24
+ var yaml = require('js-yaml');
23
25
 
24
26
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
25
27
 
26
28
  var React__default = /*#__PURE__*/_interopDefaultCompat(React);
27
29
  var Calendar__default = /*#__PURE__*/_interopDefaultCompat(Calendar);
28
30
  var AutoSizer__default = /*#__PURE__*/_interopDefaultCompat(AutoSizer);
29
- var sqlFormatter__default = /*#__PURE__*/_interopDefaultCompat(sqlFormatter);
30
31
  var Prism__default = /*#__PURE__*/_interopDefaultCompat(Prism);
32
+ var yaml__default = /*#__PURE__*/_interopDefaultCompat(yaml);
31
33
 
32
34
  const QueryEditorRow = (props) => {
33
35
  var _a, _b;
@@ -76,7 +78,7 @@ function Segment(props) {
76
78
  );
77
79
  }
78
80
 
79
- const getStyles$r = (theme) => {
81
+ const getStyles$v = (theme) => {
80
82
  const containerBorder = theme.isDark ? theme.v1.palette.dark9 : theme.v1.palette.gray5;
81
83
  return {
82
84
  container: css.css`
@@ -226,7 +228,7 @@ const getBodyStyles = (theme) => {
226
228
 
227
229
  const DatePicker = React.memo((props) => {
228
230
  const theme = ui.useTheme2();
229
- const styles = getStyles$r(theme);
231
+ const styles = getStyles$v(theme);
230
232
  const { isOpen, onClose } = props;
231
233
  if (!isOpen) {
232
234
  return null;
@@ -256,7 +258,7 @@ const Body = React.memo(({ value, onChange }) => {
256
258
  });
257
259
  Body.displayName = "Body";
258
260
 
259
- function getStyles$q() {
261
+ function getStyles$u() {
260
262
  return {
261
263
  input: css.css({
262
264
  /* hides the native Calendar picker icon given when using type=date */
@@ -272,7 +274,7 @@ const formatDate = (date) => date.toISOString().split("T")[0];
272
274
  const DatePickerWithInput = (props) => {
273
275
  const { value, onChange, className, ...rest } = props;
274
276
  const [open, setOpen] = React.useState(false);
275
- const styles = getStyles$q();
277
+ const styles = getStyles$u();
276
278
  return /* @__PURE__ */ React__default.default.createElement(React__default.default.Fragment, null, /* @__PURE__ */ React__default.default.createElement(
277
279
  ui.Input,
278
280
  {
@@ -434,7 +436,7 @@ __publicField$3(DataSourcePicker, "defaultProps", {
434
436
  });
435
437
 
436
438
  const { FormField, Switch } = ui.LegacyForms;
437
- const getStyles$p = ui.stylesFactory(() => ({
439
+ const getStyles$t = ui.stylesFactory(() => ({
438
440
  firstRow: css.css`
439
441
  display: flex;
440
442
  `,
@@ -451,7 +453,7 @@ const getStyles$p = ui.stylesFactory(() => ({
451
453
  }));
452
454
  const DataLink = (props) => {
453
455
  const { value, onChange, onDelete, suggestions, className } = props;
454
- const styles = getStyles$p();
456
+ const styles = getStyles$t();
455
457
  const [showInternalLink, setShowInternalLink] = useInternalLink(value.datasourceUid);
456
458
  const handleChange = (field) => (event) => {
457
459
  onChange({
@@ -568,7 +570,7 @@ function useInternalLink(datasourceUid) {
568
570
  return [showInternalLink, setShowInternalLink];
569
571
  }
570
572
 
571
- const getStyles$o = (theme) => ({
573
+ const getStyles$s = (theme) => ({
572
574
  infoText: css.css`
573
575
  padding-bottom: ${theme.v1.spacing.md};
574
576
  color: ${theme.v1.colors.textWeak};
@@ -580,7 +582,7 @@ const getStyles$o = (theme) => ({
580
582
  const DataLinks = (props) => {
581
583
  const { value, onChange } = props;
582
584
  const theme = ui.useTheme2();
583
- const styles = getStyles$o(theme);
585
+ const styles = getStyles$s(theme);
584
586
  return /* @__PURE__ */ React__default.default.createElement(React__default.default.Fragment, null, /* @__PURE__ */ React__default.default.createElement("h3", { className: "page-heading" }, "Data links"), /* @__PURE__ */ React__default.default.createElement("div", { className: styles.infoText }, "Add links to existing fields. Links will be shown in log row details next to the field value."), /* @__PURE__ */ React__default.default.createElement("div", { className: "gf-form-group" }, value && value.map((field, index) => {
585
587
  return /* @__PURE__ */ React__default.default.createElement(
586
588
  DataLink,
@@ -641,110 +643,21 @@ var QueryEditorExpressionType = /* @__PURE__ */ ((QueryEditorExpressionType2) =>
641
643
  return QueryEditorExpressionType2;
642
644
  })(QueryEditorExpressionType || {});
643
645
 
644
- function getRawSqlFn(db) {
645
- return db.toRawSql ? db.toRawSql : (query) => toRawSql(query, Boolean(db.disableDatasets));
646
- }
647
- function toRawSql({ sql, dataset, catalog, table }, disableDatasets) {
648
- var _a, _b, _c, _d;
649
- let rawQuery = "";
650
- if (!sql || !haveColumns(sql.columns)) {
651
- return rawQuery;
652
- }
653
- rawQuery += createSelectClause(sql.columns);
654
- if (catalog && dataset && table) {
655
- rawQuery += `FROM ${catalog}.${dataset}.${table} `;
656
- } else if (!disableDatasets && dataset && table) {
657
- rawQuery += `FROM ${dataset}.${table} `;
658
- } else if (table) {
659
- rawQuery += `FROM ${table} `;
660
- }
661
- if (sql.whereString) {
662
- rawQuery += `WHERE ${sql.whereString} `;
663
- }
664
- if ((_b = (_a = sql.groupBy) == null ? void 0 : _a[0]) == null ? void 0 : _b.property.name) {
665
- const groupBy = sql.groupBy.map((g) => g.property.name).filter((g) => !lodash.isEmpty(g));
666
- rawQuery += `GROUP BY ${groupBy.join(", ")} `;
667
- }
668
- if ((_c = sql.orderBy) == null ? void 0 : _c.property.name) {
669
- rawQuery += `ORDER BY ${sql.orderBy.property.name} `;
670
- }
671
- if (((_d = sql.orderBy) == null ? void 0 : _d.property.name) && sql.orderByDirection) {
672
- rawQuery += `${sql.orderByDirection} `;
673
- }
674
- if (sql.limit !== void 0 && sql.limit >= 0) {
675
- rawQuery += `LIMIT ${sql.limit} `;
676
- }
677
- return rawQuery;
678
- }
679
- function createSelectClause(sqlColumns) {
680
- const columns = sqlColumns.map((c) => {
681
- var _a, _b;
682
- let rawColumn = "";
683
- if (c.name) {
684
- rawColumn += `${c.name}(${(_a = c.parameters) == null ? void 0 : _a.map((p) => `${p.name}`)})`;
685
- } else {
686
- rawColumn += `${(_b = c.parameters) == null ? void 0 : _b.map((p) => `${p.name}`)}`;
687
- }
688
- return rawColumn;
689
- });
690
- return `SELECT ${columns.join(", ")} `;
691
- }
692
- function haveColumns(columns) {
693
- if (!columns) {
694
- return false;
695
- }
696
- const haveColumn = columns.some((c) => {
697
- var _a, _b;
698
- return ((_a = c.parameters) == null ? void 0 : _a.length) || ((_b = c.parameters) == null ? void 0 : _b.some((p) => p.name));
699
- });
700
- const haveFunction = columns.some((c) => c.name);
701
- return haveColumn || haveFunction;
702
- }
703
- function setGroupByField(field) {
704
- return {
705
- type: QueryEditorExpressionType.GroupBy,
706
- property: {
707
- type: QueryEditorPropertyType.String,
708
- name: field
709
- }
710
- };
711
- }
712
- function setPropertyField(field) {
713
- return {
714
- type: QueryEditorExpressionType.Property,
715
- property: {
716
- type: QueryEditorPropertyType.String,
717
- name: field
718
- }
719
- };
720
- }
721
- function createFunctionField(functionName) {
722
- return {
723
- type: QueryEditorExpressionType.Function,
724
- name: functionName,
725
- parameters: []
726
- };
727
- }
728
-
729
- function applyQueryDefaults(q) {
730
- let editorMode = (q == null ? void 0 : q.editorMode) || EditorMode.Builder;
731
- if ((q == null ? void 0 : q.editorMode) === void 0 && (q == null ? void 0 : q.rawSql) !== void 0) {
732
- editorMode = EditorMode.Code;
733
- }
734
- const result = {
735
- ...q,
736
- refId: (q == null ? void 0 : q.refId) || "A",
737
- format: (q == null ? void 0 : q.format) !== void 0 ? q.format : QueryFormat.Table,
738
- rawSql: (q == null ? void 0 : q.rawSql) || "",
739
- editorMode,
740
- sql: (q == null ? void 0 : q.sql) || {
741
- columns: [createFunctionField()],
742
- groupBy: [setGroupByField()],
743
- limit: 50
744
- }
745
- };
746
- return result;
747
- }
646
+ var TokenType = /* @__PURE__ */ ((TokenType2) => {
647
+ TokenType2["Parenthesis"] = "delimiter.parenthesis.sql";
648
+ TokenType2["Whitespace"] = "white.sql";
649
+ TokenType2["Keyword"] = "keyword.sql";
650
+ TokenType2["Delimiter"] = "delimiter.sql";
651
+ TokenType2["Operator"] = "operator.sql";
652
+ TokenType2["Identifier"] = "identifier.sql";
653
+ TokenType2["IdentifierQuote"] = "identifier.quote.sql";
654
+ TokenType2["Type"] = "type.sql";
655
+ TokenType2["Function"] = "predefined.sql";
656
+ TokenType2["Number"] = "number.sql";
657
+ TokenType2["String"] = "string.sql";
658
+ TokenType2["Variable"] = "variable.sql";
659
+ return TokenType2;
660
+ })(TokenType || {});
748
661
 
749
662
  class LinkedToken {
750
663
  constructor(type, value, range, previous, next) {
@@ -899,21 +812,6 @@ var MacroType = /* @__PURE__ */ ((MacroType2) => {
899
812
  MacroType2[MacroType2["Table"] = 4] = "Table";
900
813
  return MacroType2;
901
814
  })(MacroType || {});
902
- var TokenType = /* @__PURE__ */ ((TokenType2) => {
903
- TokenType2["Parenthesis"] = "delimiter.parenthesis.sql";
904
- TokenType2["Whitespace"] = "white.sql";
905
- TokenType2["Keyword"] = "keyword.sql";
906
- TokenType2["Delimiter"] = "delimiter.sql";
907
- TokenType2["Operator"] = "operator.sql";
908
- TokenType2["Identifier"] = "identifier.sql";
909
- TokenType2["IdentifierQuote"] = "identifier.quote.sql";
910
- TokenType2["Type"] = "type.sql";
911
- TokenType2["Function"] = "predefined.sql";
912
- TokenType2["Number"] = "number.sql";
913
- TokenType2["String"] = "string.sql";
914
- TokenType2["Variable"] = "variable.sql";
915
- return TokenType2;
916
- })(TokenType || {});
917
815
  var StatementPosition = /* @__PURE__ */ ((StatementPosition2) => {
918
816
  StatementPosition2["Unknown"] = "unknown";
919
817
  StatementPosition2["SelectKeyword"] = "selectKeyword";
@@ -5456,6 +5354,91 @@ const QUERY_FORMAT_OPTIONS = [
5456
5354
  const backWardToOption = (value) => ({ label: value, value });
5457
5355
  const toOption = (_a = data.toOption) != null ? _a : backWardToOption;
5458
5356
 
5357
+ function getRawSqlFn(db) {
5358
+ return db.toRawSql ? db.toRawSql : (query) => toRawSql(query, Boolean(db.disableDatasets));
5359
+ }
5360
+ function toRawSql({ sql, dataset, catalog, table }, disableDatasets) {
5361
+ var _a, _b, _c, _d;
5362
+ let rawQuery = "";
5363
+ if (!sql || !haveColumns(sql.columns)) {
5364
+ return rawQuery;
5365
+ }
5366
+ rawQuery += createSelectClause(sql.columns);
5367
+ if (catalog && dataset && table) {
5368
+ rawQuery += `FROM ${catalog}.${dataset}.${table} `;
5369
+ } else if (!disableDatasets && dataset && table) {
5370
+ rawQuery += `FROM ${dataset}.${table} `;
5371
+ } else if (table) {
5372
+ rawQuery += `FROM ${table} `;
5373
+ }
5374
+ if (sql.whereString) {
5375
+ rawQuery += `WHERE ${sql.whereString} `;
5376
+ }
5377
+ if ((_b = (_a = sql.groupBy) == null ? void 0 : _a[0]) == null ? void 0 : _b.property.name) {
5378
+ const groupBy = sql.groupBy.map((g) => g.property.name).filter((g) => !lodash.isEmpty(g));
5379
+ rawQuery += `GROUP BY ${groupBy.join(", ")} `;
5380
+ }
5381
+ if ((_c = sql.orderBy) == null ? void 0 : _c.property.name) {
5382
+ rawQuery += `ORDER BY ${sql.orderBy.property.name} `;
5383
+ }
5384
+ if (((_d = sql.orderBy) == null ? void 0 : _d.property.name) && sql.orderByDirection) {
5385
+ rawQuery += `${sql.orderByDirection} `;
5386
+ }
5387
+ if (sql.limit !== void 0 && sql.limit >= 0) {
5388
+ rawQuery += `LIMIT ${sql.limit} `;
5389
+ }
5390
+ return rawQuery;
5391
+ }
5392
+ function createSelectClause(sqlColumns) {
5393
+ const columns = sqlColumns.map((c) => {
5394
+ var _a, _b;
5395
+ let rawColumn = "";
5396
+ if (c.name) {
5397
+ rawColumn += `${c.name}(${(_a = c.parameters) == null ? void 0 : _a.map((p) => `${p.name}`)})`;
5398
+ } else {
5399
+ rawColumn += `${(_b = c.parameters) == null ? void 0 : _b.map((p) => `${p.name}`)}`;
5400
+ }
5401
+ return rawColumn;
5402
+ });
5403
+ return `SELECT ${columns.join(", ")} `;
5404
+ }
5405
+ function haveColumns(columns) {
5406
+ if (!columns) {
5407
+ return false;
5408
+ }
5409
+ const haveColumn = columns.some((c) => {
5410
+ var _a, _b;
5411
+ return ((_a = c.parameters) == null ? void 0 : _a.length) || ((_b = c.parameters) == null ? void 0 : _b.some((p) => p.name));
5412
+ });
5413
+ const haveFunction = columns.some((c) => c.name);
5414
+ return haveColumn || haveFunction;
5415
+ }
5416
+ function setGroupByField(field) {
5417
+ return {
5418
+ type: QueryEditorExpressionType.GroupBy,
5419
+ property: {
5420
+ type: QueryEditorPropertyType.String,
5421
+ name: field
5422
+ }
5423
+ };
5424
+ }
5425
+ function setPropertyField(field) {
5426
+ return {
5427
+ type: QueryEditorExpressionType.Property,
5428
+ property: {
5429
+ type: QueryEditorPropertyType.String,
5430
+ name: field
5431
+ }
5432
+ };
5433
+ }
5434
+ function createFunctionField(functionName) {
5435
+ return {
5436
+ type: QueryEditorExpressionType.Function,
5437
+ name: functionName,
5438
+ parameters: []
5439
+ };
5440
+ }
5441
+
5459
5442
  const EditorStack = ({ children, wrap: wrapItems = true, ...props }) => {
5460
5443
  var _a, _b;
5461
5444
  return /* @__PURE__ */ React__default.default.createElement(ui.Stack, { wrap: wrapItems ? "wrap" : void 0, direction: (_a = props.direction) != null ? _a : "row", gap: (_b = props.gap) != null ? _b : 2, ...props }, children);
@@ -5495,7 +5478,7 @@ const getButtonStyles = (theme) => ({
5495
5478
  });
5496
5479
 
5497
5480
  const InputGroup = ({ children }) => {
5498
- const styles = ui.useStyles2(getStyles$n);
5481
+ const styles = ui.useStyles2(getStyles$r);
5499
5482
  const modifiedChildren = React.Children.map(children, (child) => {
5500
5483
  if (React.isValidElement(child) && child.props.invalid) {
5501
5484
  return React.cloneElement(child, { className: css.cx(child.props.className, styles.invalidChild) });
@@ -5513,7 +5496,7 @@ const borderPriority = [
5513
5496
  "focused"
5514
5497
  // highest priority
5515
5498
  ];
5516
- const getStyles$n = () => ({
5499
+ const getStyles$r = () => ({
5517
5500
  root: css.css({
5518
5501
  display: "flex",
5519
5502
  // Style the direct children of the component
@@ -5596,10 +5579,10 @@ const EditorFieldGroup = ({ children }) => {
5596
5579
  };
5597
5580
 
5598
5581
  const EditorHeader = ({ children }) => {
5599
- const styles = ui.useStyles2(getStyles$m);
5582
+ const styles = ui.useStyles2(getStyles$q);
5600
5583
  return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.root }, children);
5601
5584
  };
5602
- const getStyles$m = (theme) => ({
5585
+ const getStyles$q = (theme) => ({
5603
5586
  root: css.css({
5604
5587
  display: "flex",
5605
5588
  flexWrap: "wrap",
@@ -5612,12 +5595,12 @@ const getStyles$m = (theme) => ({
5612
5595
  const EditorField$1 = (props) => {
5613
5596
  var _a;
5614
5597
  const { label, optional, tooltip, tooltipInteractive, children, width, ...fieldProps } = props;
5615
- const styles = ui.useStyles2(getStyles$l, width);
5598
+ const styles = ui.useStyles2(getStyles$p, width);
5616
5599
  const childInputId = (fieldProps == null ? void 0 : fieldProps.htmlFor) || ((_a = ui.ReactUtils) == null ? void 0 : _a.getChildId(children));
5617
5600
  const labelEl = /* @__PURE__ */ React__default.default.createElement(React__default.default.Fragment, null, /* @__PURE__ */ React__default.default.createElement("label", { className: styles.label, htmlFor: childInputId }, label, optional && /* @__PURE__ */ React__default.default.createElement("span", { className: styles.optional }, " - optional"), tooltip && /* @__PURE__ */ React__default.default.createElement(ui.Tooltip, { placement: "top", content: tooltip, theme: "info", interactive: tooltipInteractive }, /* @__PURE__ */ React__default.default.createElement(ui.Icon, { tabIndex: 0, name: "info-circle", size: "sm", className: styles.icon }))), /* @__PURE__ */ React__default.default.createElement(ui.Space, { v: 0.5 }));
5618
5601
  return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.root }, /* @__PURE__ */ React__default.default.createElement(ui.Field, { className: styles.field, label: labelEl, ...fieldProps }, children));
5619
5602
  };
5620
- const getStyles$l = (theme, width) => {
5603
+ const getStyles$p = (theme, width) => {
5621
5604
  return {
5622
5605
  root: css.css({
5623
5606
  minWidth: theme.spacing(width != null ? width : 0)
@@ -5645,10 +5628,10 @@ const getStyles$l = (theme, width) => {
5645
5628
  };
5646
5629
 
5647
5630
  const EditorRow$1 = ({ children }) => {
5648
- const styles = ui.useStyles2(getStyles$k);
5631
+ const styles = ui.useStyles2(getStyles$o);
5649
5632
  return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.root }, /* @__PURE__ */ React__default.default.createElement(EditorStack, { gap: 2 }, children));
5650
5633
  };
5651
- const getStyles$k = (theme) => {
5634
+ const getStyles$o = (theme) => {
5652
5635
  return {
5653
5636
  root: css.css({
5654
5637
  padding: theme.spacing(1),
@@ -5663,10 +5646,10 @@ const EditorRows$1 = ({ children }) => {
5663
5646
  };
5664
5647
 
5665
5648
  const EditorSwitch = (props) => {
5666
- const styles = getStyles$j();
5649
+ const styles = getStyles$n();
5667
5650
  return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.switch }, /* @__PURE__ */ React__default.default.createElement(ui.Switch, { ...props }));
5668
5651
  };
5669
- const getStyles$j = () => {
5652
+ const getStyles$n = () => {
5670
5653
  return {
5671
5654
  switch: css.css({
5672
5655
  display: "flex",
@@ -5688,7 +5671,7 @@ function InlineSelect({ label: labelProp, ...props }) {
5688
5671
  ValueContainer,
5689
5672
  SingleValue: ValueContainer
5690
5673
  };
5691
- return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.root }, labelProp && /* @__PURE__ */ React__default.default.createElement("label", { className: styles.label, htmlFor: id }, labelProp, ":", "\xA0"), /* @__PURE__ */ React__default.default.createElement(ui.Select, { openMenuOnFocus: true, inputId: id, ...props, components }));
5674
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.root }, labelProp && /* @__PURE__ */ React__default.default.createElement("label", { className: styles.label, htmlFor: id }, labelProp, ":", "\xA0"), /* @__PURE__ */ React__default.default.createElement(ui.Select, { inputId: id, ...props, components }));
5692
5675
  }
5693
5676
  const SelectContainer = (props) => {
5694
5677
  const { children } = props;
@@ -5724,10 +5707,10 @@ const getSelectStyles = (theme) => ({
5724
5707
  });
5725
5708
 
5726
5709
  const Space = ({ v = 0, h = 0, layout = "block" }) => {
5727
- const styles = ui.useStyles2(getStyles$i, v, h, layout);
5710
+ const styles = ui.useStyles2(getStyles$m, v, h, layout);
5728
5711
  return /* @__PURE__ */ React__default.default.createElement("span", { className: css.cx(styles.wrapper) });
5729
5712
  };
5730
- const getStyles$i = (theme, v, h, layout) => ({
5713
+ const getStyles$m = (theme, v, h, layout) => ({
5731
5714
  wrapper: css.css([
5732
5715
  {
5733
5716
  paddingRight: theme.spacing(h != null ? h : 0),
@@ -5742,6 +5725,26 @@ const getStyles$i = (theme, v, h, layout) => ({
5742
5725
  ])
5743
5726
  });
5744
5727
 
5728
+ function applyQueryDefaults(q) {
5729
+ let editorMode = (q == null ? void 0 : q.editorMode) || EditorMode.Builder;
5730
+ if ((q == null ? void 0 : q.editorMode) === void 0 && (q == null ? void 0 : q.rawSql) !== void 0) {
5731
+ editorMode = EditorMode.Code;
5732
+ }
5733
+ const result = {
5734
+ ...q,
5735
+ refId: (q == null ? void 0 : q.refId) || "A",
5736
+ format: (q == null ? void 0 : q.format) !== void 0 ? q.format : QueryFormat.Table,
5737
+ rawSql: (q == null ? void 0 : q.rawSql) || "",
5738
+ editorMode,
5739
+ sql: (q == null ? void 0 : q.sql) || {
5740
+ columns: [createFunctionField()],
5741
+ groupBy: [setGroupByField()],
5742
+ limit: 50
5743
+ }
5744
+ };
5745
+ return result;
5746
+ }
5747
+
5745
5748
  function ConfirmModal({ isOpen, onCancel, onDiscard, onCopy }) {
5746
5749
  const buttonRef = React.useRef(null);
5747
5750
  React.useEffect(() => {
@@ -6131,13 +6134,32 @@ function QueryHeader({
6131
6134
  )))));
6132
6135
  }
6133
6136
 
6134
- function formatSQL(q) {
6135
- return sqlFormatter__default.default.format(q).replace(/(\$ \{ .* \})|(\$ __)|(\$ \w+)/g, (m) => {
6136
- return m.replace(/\s/g, "");
6137
+ function formatSQL(q, language = "sql") {
6138
+ const formatted = sqlFormatter.format(q, {
6139
+ language,
6140
+ paramTypes: {
6141
+ custom: [
6142
+ {
6143
+ regex: "\\$\\s*\\{[^}]*\\}|\\$\\s*__\\w+(?:\\([^)]*\\))?|\\$\\s*\\w+"
6144
+ }
6145
+ ]
6146
+ }
6137
6147
  });
6148
+ return formatted.replace(
6149
+ /(\$\s*\{[^}]*\})|(\$\s*__\w+(?:\([^)]*\))?)|(\$\s*\w+)/g,
6150
+ (m) => m.replace(/\s/g, "")
6151
+ );
6138
6152
  }
6139
6153
 
6140
- function QueryEditorRaw({ children, onChange, query, width, height, completionProvider }) {
6154
+ function QueryEditorRaw({
6155
+ children,
6156
+ onChange,
6157
+ query,
6158
+ width,
6159
+ height,
6160
+ completionProvider,
6161
+ language = "sql"
6162
+ }) {
6141
6163
  const queryRef = React.useRef(query);
6142
6164
  React.useEffect(() => {
6143
6165
  queryRef.current = query;
@@ -6160,7 +6182,7 @@ function QueryEditorRaw({ children, onChange, query, width, height, completionPr
6160
6182
  height,
6161
6183
  query: query.rawSql,
6162
6184
  onChange: onRawQueryChange,
6163
- language: { id: "sql", completionProvider, formatter: formatSQL }
6185
+ language: { id: "sql", completionProvider, formatter: (q) => formatSQL(q, language) }
6164
6186
  },
6165
6187
  children
6166
6188
  );
@@ -6265,6 +6287,10 @@ function QueryToolbox({ showTools, onFormatCode, onExpand, isExpanded, ...valida
6265
6287
  if (!showTools && validationResult === void 0) {
6266
6288
  style = { height: 0, padding: 0, visibility: "hidden" };
6267
6289
  }
6290
+ const onFormatClick = () => {
6291
+ runtime.reportInteraction("grafana_sql_query_editor_format_click");
6292
+ onFormatCode == null ? void 0 : onFormatCode();
6293
+ };
6268
6294
  return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.container, style }, /* @__PURE__ */ React__default.default.createElement("div", null, validatorProps.onValidate && /* @__PURE__ */ React__default.default.createElement(
6269
6295
  QueryValidator,
6270
6296
  {
@@ -6274,7 +6300,7 @@ function QueryToolbox({ showTools, onFormatCode, onExpand, isExpanded, ...valida
6274
6300
  validatorProps.onValidate(result);
6275
6301
  }
6276
6302
  }
6277
- )), showTools && /* @__PURE__ */ React__default.default.createElement("div", null, /* @__PURE__ */ React__default.default.createElement(ui.HorizontalGroup, { spacing: "sm" }, onFormatCode && /* @__PURE__ */ React__default.default.createElement(ui.IconButton, { onClick: onFormatCode, name: "brackets-curly", size: "xs", tooltip: "Format query" }), onExpand && /* @__PURE__ */ React__default.default.createElement(
6303
+ )), showTools && /* @__PURE__ */ React__default.default.createElement("div", null, /* @__PURE__ */ React__default.default.createElement(ui.HorizontalGroup, { spacing: "sm" }, onFormatCode && /* @__PURE__ */ React__default.default.createElement(ui.IconButton, { onClick: onFormatClick, name: "brackets-curly", size: "xs", tooltip: "Format query" }), onExpand && /* @__PURE__ */ React__default.default.createElement(
6278
6304
  ui.IconButton,
6279
6305
  {
6280
6306
  onClick: () => onExpand(!isExpanded),
@@ -6285,10 +6311,19 @@ function QueryToolbox({ showTools, onFormatCode, onExpand, isExpanded, ...valida
6285
6311
  ), /* @__PURE__ */ React__default.default.createElement(ui.Tooltip, { content: "Hit CTRL/CMD+Return to run query" }, /* @__PURE__ */ React__default.default.createElement(ui.Icon, { className: styles.hint, name: "keyboard" })))));
6286
6312
  }
6287
6313
 
6288
- function RawEditor({ db, query, onChange, onRunQuery, onValidate, queryToValidate, range }) {
6289
- const theme = ui.useTheme2();
6290
- const styles = ui.useStyles2(getStyles$h);
6291
- const [isExpanded, setIsExpanded] = React.useState(false);
6314
+ function RawEditor({
6315
+ db,
6316
+ query,
6317
+ onChange,
6318
+ onRunQuery,
6319
+ onValidate,
6320
+ queryToValidate,
6321
+ range,
6322
+ language = "sql"
6323
+ }) {
6324
+ const theme = ui.useTheme2();
6325
+ const styles = ui.useStyles2(getStyles$l);
6326
+ const [isExpanded, setIsExpanded] = React.useState(false);
6292
6327
  const [toolboxRef, toolboxMeasure] = reactUse.useMeasure();
6293
6328
  const [editorRef, editorMeasure] = reactUse.useMeasure();
6294
6329
  const completionProvider = React.useMemo(() => db.getSqlCompletionProvider(), [db]);
@@ -6299,6 +6334,7 @@ function RawEditor({ db, query, onChange, onRunQuery, onValidate, queryToValidat
6299
6334
  completionProvider,
6300
6335
  query,
6301
6336
  width,
6337
+ language,
6302
6338
  height: height ? height - toolboxMeasure.height : void 0,
6303
6339
  onChange
6304
6340
  },
@@ -6356,7 +6392,7 @@ function RawEditor({ db, query, onChange, onRunQuery, onValidate, queryToValidat
6356
6392
  renderEditor(true)
6357
6393
  ));
6358
6394
  }
6359
- function getStyles$h(theme) {
6395
+ function getStyles$l(theme) {
6360
6396
  return {
6361
6397
  modal: css.css`
6362
6398
  width: 95vw;
@@ -6369,23 +6405,23 @@ function getStyles$h(theme) {
6369
6405
  };
6370
6406
  }
6371
6407
 
6372
- function Preview({ rawSql }) {
6408
+ function Preview({ rawSql, language = "sql" }) {
6373
6409
  const [_, copyToClipboard] = reactUse.useCopyToClipboard();
6374
- const styles = ui.useStyles2(getStyles$g);
6410
+ const styles = ui.useStyles2(getStyles$k);
6375
6411
  const labelElement = /* @__PURE__ */ React__default.default.createElement("div", { className: styles.labelWrapper }, /* @__PURE__ */ React__default.default.createElement("label", { className: styles.label }, "Preview"), /* @__PURE__ */ React__default.default.createElement(ui.IconButton, { tooltip: "Copy to clipboard", onClick: () => copyToClipboard(rawSql), name: "copy" }));
6376
6412
  return /* @__PURE__ */ React__default.default.createElement(ui.Field, { label: labelElement, className: styles.grow }, /* @__PURE__ */ React__default.default.createElement(
6377
6413
  ui.CodeEditor,
6378
6414
  {
6379
6415
  language: "sql",
6380
6416
  height: 80,
6381
- value: formatSQL(rawSql),
6417
+ value: formatSQL(rawSql, language),
6382
6418
  monacoOptions: { scrollbar: { vertical: "hidden" }, scrollBeyondLastLine: false },
6383
6419
  readOnly: true,
6384
6420
  showMiniMap: false
6385
6421
  }
6386
6422
  ));
6387
6423
  }
6388
- function getStyles$g(theme) {
6424
+ function getStyles$k(theme) {
6389
6425
  return {
6390
6426
  grow: css.css({ flexGrow: 1 }),
6391
6427
  label: css.css({ fontSize: 12, fontWeight: theme.typography.fontWeightMedium }),
@@ -6504,7 +6540,7 @@ function SQLOrderByRow({ fields, query, onQueryChange, db }) {
6504
6540
  const asteriskValue = { label: "*", value: "*" };
6505
6541
  function SelectRow({ sql, columns, onSqlChange, functions }) {
6506
6542
  var _a;
6507
- const styles = ui.useStyles2(getStyles$f);
6543
+ const styles = ui.useStyles2(getStyles$j);
6508
6544
  const columnsWithAsterisk = [asteriskValue, ...columns || []];
6509
6545
  const onColumnChange = React.useCallback(
6510
6546
  (item, index) => (column) => {
@@ -6600,7 +6636,7 @@ function SelectRow({ sql, columns, onSqlChange, functions }) {
6600
6636
  }
6601
6637
  ));
6602
6638
  }
6603
- const getStyles$f = () => {
6639
+ const getStyles$j = () => {
6604
6640
  return { addButton: css.css({ alignSelf: "flex-start" }) };
6605
6641
  };
6606
6642
  function getColumnValue({ parameters }) {
@@ -6946,10 +6982,10 @@ function mapFieldsToTypes(columns) {
6946
6982
  }
6947
6983
 
6948
6984
  const EditorRow = ({ children }) => {
6949
- const styles = ui.useStyles2(getStyles$e);
6985
+ const styles = ui.useStyles2(getStyles$i);
6950
6986
  return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.root }, /* @__PURE__ */ React__default.default.createElement(EditorStack, { gap: 2 }, children));
6951
6987
  };
6952
- const getStyles$e = (theme) => {
6988
+ const getStyles$i = (theme) => {
6953
6989
  return {
6954
6990
  root: css.css({
6955
6991
  padding: theme.spacing(1),
@@ -6963,12 +6999,12 @@ const EditorField = (props) => {
6963
6999
  var _a;
6964
7000
  const { label, optional, tooltip, children, width, ...fieldProps } = props;
6965
7001
  const theme = ui.useTheme2();
6966
- const styles = getStyles$d(theme, width);
7002
+ const styles = getStyles$h(theme, width);
6967
7003
  const childInputId = (fieldProps == null ? void 0 : fieldProps.htmlFor) || ((_a = ui.ReactUtils) == null ? void 0 : _a.getChildId(children));
6968
7004
  const labelEl = /* @__PURE__ */ React__default.default.createElement(React__default.default.Fragment, null, /* @__PURE__ */ React__default.default.createElement("label", { className: styles.label, htmlFor: childInputId }, label, optional && /* @__PURE__ */ React__default.default.createElement("span", { className: styles.optional }, " - optional"), tooltip && /* @__PURE__ */ React__default.default.createElement(ui.Tooltip, { placement: "top", content: tooltip, theme: "info" }, /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "info-circle", size: "sm", className: styles.icon }))), /* @__PURE__ */ React__default.default.createElement(Space, { v: 0.5 }));
6969
7005
  return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.root }, /* @__PURE__ */ React__default.default.createElement(ui.Field, { className: styles.field, label: labelEl, ...fieldProps }, children));
6970
7006
  };
6971
- const getStyles$d = ui.stylesFactory((theme, width) => {
7007
+ const getStyles$h = ui.stylesFactory((theme, width) => {
6972
7008
  return {
6973
7009
  root: css.css({
6974
7010
  minWidth: theme.spacing(width != null ? width : 0)
@@ -6999,12 +7035,20 @@ const EditorRows = ({ children }) => {
6999
7035
  return /* @__PURE__ */ React__default.default.createElement(EditorStack, { gap: 0.5, direction: "column" }, children);
7000
7036
  };
7001
7037
 
7002
- const VisualEditor = ({ query, db, queryRowFilter, onChange, onValidate, range }) => {
7038
+ const VisualEditor = ({
7039
+ query,
7040
+ db,
7041
+ queryRowFilter,
7042
+ onChange,
7043
+ onValidate,
7044
+ language = "sql",
7045
+ range
7046
+ }) => {
7003
7047
  const state = reactUse.useAsync(async () => {
7004
7048
  const fields = await db.fields(query);
7005
7049
  return fields;
7006
7050
  }, [db, query.dataset, query.table]);
7007
- return /* @__PURE__ */ React__default.default.createElement(React__default.default.Fragment, null, /* @__PURE__ */ React__default.default.createElement(EditorRows, null, /* @__PURE__ */ React__default.default.createElement(EditorRow, null, /* @__PURE__ */ React__default.default.createElement(SQLSelectRow, { fields: state.value || [], query, onQueryChange: onChange, db })), queryRowFilter.filter && /* @__PURE__ */ React__default.default.createElement(EditorRow, null, /* @__PURE__ */ React__default.default.createElement(EditorField, { label: "Filter by column value", optional: true }, /* @__PURE__ */ React__default.default.createElement(SQLWhereRow, { fields: state.value || [], query, onQueryChange: onChange, db }))), queryRowFilter.group && /* @__PURE__ */ React__default.default.createElement(EditorRow, null, /* @__PURE__ */ React__default.default.createElement(EditorField, { label: "Group by column" }, /* @__PURE__ */ React__default.default.createElement(SQLGroupByRow, { fields: state.value || [], query, onQueryChange: onChange, db }))), queryRowFilter.order && /* @__PURE__ */ React__default.default.createElement(EditorRow, null, /* @__PURE__ */ React__default.default.createElement(SQLOrderByRow, { fields: state.value || [], query, onQueryChange: onChange, db })), queryRowFilter.preview && query.rawSql && /* @__PURE__ */ React__default.default.createElement(EditorRow, null, /* @__PURE__ */ React__default.default.createElement(Preview, { rawSql: query.rawSql }))), /* @__PURE__ */ React__default.default.createElement(QueryToolbox, { db, query, onValidate, range }));
7051
+ return /* @__PURE__ */ React__default.default.createElement(React__default.default.Fragment, null, /* @__PURE__ */ React__default.default.createElement(EditorRows, null, /* @__PURE__ */ React__default.default.createElement(EditorRow, null, /* @__PURE__ */ React__default.default.createElement(SQLSelectRow, { fields: state.value || [], query, onQueryChange: onChange, db })), queryRowFilter.filter && /* @__PURE__ */ React__default.default.createElement(EditorRow, null, /* @__PURE__ */ React__default.default.createElement(EditorField, { label: "Filter by column value", optional: true }, /* @__PURE__ */ React__default.default.createElement(SQLWhereRow, { fields: state.value || [], query, onQueryChange: onChange, db }))), queryRowFilter.group && /* @__PURE__ */ React__default.default.createElement(EditorRow, null, /* @__PURE__ */ React__default.default.createElement(EditorField, { label: "Group by column" }, /* @__PURE__ */ React__default.default.createElement(SQLGroupByRow, { fields: state.value || [], query, onQueryChange: onChange, db }))), queryRowFilter.order && /* @__PURE__ */ React__default.default.createElement(EditorRow, null, /* @__PURE__ */ React__default.default.createElement(SQLOrderByRow, { fields: state.value || [], query, onQueryChange: onChange, db })), queryRowFilter.preview && query.rawSql && /* @__PURE__ */ React__default.default.createElement(EditorRow, null, /* @__PURE__ */ React__default.default.createElement(Preview, { rawSql: query.rawSql, language }))), /* @__PURE__ */ React__default.default.createElement(QueryToolbox, { db, query, onValidate, range }));
7008
7052
  };
7009
7053
 
7010
7054
  const MACRO_NAMES = [
@@ -7186,7 +7230,7 @@ const getSearchFilterScopedVar = (args) => {
7186
7230
  };
7187
7231
  };
7188
7232
 
7189
- function SqlQueryEditor({ datasource, query, onChange, onRunQuery, range }) {
7233
+ function SqlQueryEditor({ datasource, query, onChange, onRunQuery, range, language = "sql" }) {
7190
7234
  var _a, _b, _c, _d, _e, _f, _g;
7191
7235
  const [isQueryRunnable, setIsQueryRunnable] = React.useState(true);
7192
7236
  const db = datasource.getDB();
@@ -7262,6 +7306,7 @@ function SqlQueryEditor({ datasource, query, onChange, onRunQuery, range }) {
7262
7306
  {
7263
7307
  db,
7264
7308
  query: queryWithDefaults,
7309
+ language,
7265
7310
  onChange: (q) => onQueryChange(q, false),
7266
7311
  queryRowFilter,
7267
7312
  onValidate: setIsQueryRunnable,
@@ -7271,6 +7316,7 @@ function SqlQueryEditor({ datasource, query, onChange, onRunQuery, range }) {
7271
7316
  RawEditor,
7272
7317
  {
7273
7318
  db,
7319
+ language,
7274
7320
  query: queryWithDefaults,
7275
7321
  queryToValidate,
7276
7322
  onChange: onQueryChange,
@@ -7408,7 +7454,7 @@ const ConfigSubSection = ({ children, ...props }) => {
7408
7454
  function ConfigDescriptionLink(props) {
7409
7455
  const { description, suffix, feature } = props;
7410
7456
  const text = `Learn more about ${feature}`;
7411
- const styles = ui.useStyles2(getStyles$c);
7457
+ const styles = ui.useStyles2(getStyles$g);
7412
7458
  return /* @__PURE__ */ React__default.default.createElement("span", { className: styles.container }, description, /* @__PURE__ */ React__default.default.createElement(
7413
7459
  "a",
7414
7460
  {
@@ -7420,7 +7466,7 @@ function ConfigDescriptionLink(props) {
7420
7466
  text
7421
7467
  ));
7422
7468
  }
7423
- const getStyles$c = (theme) => {
7469
+ const getStyles$g = (theme) => {
7424
7470
  return {
7425
7471
  container: css.css({
7426
7472
  color: theme.colors.text.secondary,
@@ -8389,229 +8435,2315 @@ const AdvancedHttpSettings = ({
8389
8435
  ));
8390
8436
  };
8391
8437
 
8392
- var __defProp$1 = Object.defineProperty;
8393
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8394
- var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
8395
- const getCustomHeaderRowStyles = ui.stylesFactory(() => {
8396
- return {
8397
- layout: css.css`
8398
- display: flex;
8399
- align-items: center;
8400
- margin-bottom: 4px;
8401
- > * {
8402
- margin-left: 4px;
8403
- margin-bottom: 0;
8404
- height: 100%;
8405
- &:first-child,
8406
- &:last-child {
8407
- margin-left: 0;
8408
- }
8409
- }
8410
- `
8411
- };
8412
- });
8413
- const CustomHeaderRow = ({ header, onBlur, onChange, onRemove, onReset }) => {
8414
- const styles = getCustomHeaderRowStyles();
8415
- return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.layout }, /* @__PURE__ */ React__default.default.createElement(
8416
- ui.LegacyForms.FormField,
8438
+ function resolveGroups(schema) {
8439
+ const fieldMap = /* @__PURE__ */ new Map();
8440
+ for (const f of schema.fields) {
8441
+ fieldMap.set(f.id, f);
8442
+ }
8443
+ if (schema.groups && schema.groups.length > 0) {
8444
+ return schema.groups.slice().sort((a, b) => {
8445
+ var _a, _b;
8446
+ return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
8447
+ }).map((g) => ({
8448
+ group: g,
8449
+ fields: g.fieldRefs.map((ref) => fieldMap.get(ref)).filter((f) => f != null)
8450
+ }));
8451
+ }
8452
+ const allFields = schema.fields.filter((f) => f.kind !== "virtual" && !f.isItemField);
8453
+ return [
8417
8454
  {
8418
- label: "Header",
8419
- name: "name",
8420
- placeholder: "X-Custom-Header",
8421
- labelWidth: 5,
8422
- value: header.name || "",
8423
- onChange: (e) => onChange({ ...header, name: e.target.value }),
8424
- onBlur
8455
+ group: { id: "default", title: "Configuration", fieldRefs: allFields.map((f) => f.id) },
8456
+ fields: allFields
8425
8457
  }
8426
- ), /* @__PURE__ */ React__default.default.createElement(
8427
- ui.LegacyForms.SecretFormField,
8428
- {
8429
- label: "Value",
8430
- "aria-label": "Value",
8431
- name: "value",
8432
- isConfigured: header.configured,
8433
- value: header.value,
8434
- labelWidth: 5,
8435
- inputWidth: header.configured ? 11 : 12,
8436
- placeholder: "Header Value",
8437
- onReset: () => onReset(header.id),
8438
- onChange: (e) => onChange({ ...header, value: e.target.value }),
8439
- onBlur
8458
+ ];
8459
+ }
8460
+ function resolveRequiredFieldsGroup(schema) {
8461
+ var _a;
8462
+ const fieldMap = /* @__PURE__ */ new Map();
8463
+ for (const f of schema.fields) {
8464
+ fieldMap.set(f.id, f);
8465
+ }
8466
+ const requiredIds = /* @__PURE__ */ new Set();
8467
+ for (const f of schema.fields) {
8468
+ if (f.required) {
8469
+ requiredIds.add(f.id);
8440
8470
  }
8441
- ), /* @__PURE__ */ React__default.default.createElement(
8442
- ui.Button,
8443
- {
8444
- type: "button",
8445
- "aria-label": "Remove header",
8446
- variant: "secondary",
8447
- size: "xs",
8448
- onClick: (_e) => onRemove(header.id)
8449
- },
8450
- /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "trash-alt" })
8451
- ));
8452
- };
8453
- CustomHeaderRow.displayName = "CustomHeaderRow";
8454
- class CustomHeadersSettings extends React.PureComponent {
8455
- constructor(props) {
8456
- super(props);
8457
- __publicField$1(this, "state", {
8458
- headers: []
8459
- });
8460
- __publicField$1(this, "updateSettings", () => {
8461
- const { headers } = this.state;
8462
- const newJsonData = Object.fromEntries(
8463
- Object.entries(this.props.dataSourceConfig.jsonData).filter(([key, val]) => !key.startsWith("httpHeaderName"))
8464
- );
8465
- const newSecureJsonData = Object.fromEntries(
8466
- Object.entries(this.props.dataSourceConfig.secureJsonData || {}).filter(
8467
- ([key, val]) => !key.startsWith("httpHeaderValue")
8468
- )
8469
- );
8470
- for (const [index, header] of headers.entries()) {
8471
- newJsonData[`httpHeaderName${index + 1}`] = header.name;
8472
- if (!header.configured) {
8473
- newSecureJsonData[`httpHeaderValue${index + 1}`] = header.value;
8474
- }
8471
+ }
8472
+ const authGroup = (_a = schema.groups) == null ? void 0 : _a.find((g) => g.id === "auth");
8473
+ if (authGroup) {
8474
+ for (const ref of authGroup.fieldRefs) {
8475
+ if (fieldMap.has(ref)) {
8476
+ requiredIds.add(ref);
8475
8477
  }
8476
- this.props.onChange({
8477
- ...this.props.dataSourceConfig,
8478
- jsonData: newJsonData,
8479
- secureJsonData: newSecureJsonData
8480
- });
8481
- });
8482
- __publicField$1(this, "onHeaderAdd", () => {
8483
- this.setState((prevState) => {
8484
- return {
8485
- headers: [...prevState.headers, { id: lodash.uniqueId(), name: "", value: "", configured: false }]
8486
- };
8487
- });
8488
- });
8489
- __publicField$1(this, "onHeaderChange", (headerIndex, value) => {
8490
- this.setState(({ headers }) => {
8491
- return {
8492
- headers: headers.map((item, index) => {
8493
- if (headerIndex !== index) {
8494
- return item;
8495
- }
8496
- return { ...value };
8497
- })
8498
- };
8499
- });
8500
- });
8501
- __publicField$1(this, "onHeaderReset", (headerId) => {
8502
- this.setState(({ headers }) => {
8503
- return {
8504
- headers: headers.map((h, i) => {
8505
- if (h.id !== headerId) {
8506
- return h;
8507
- }
8508
- return {
8509
- ...h,
8510
- value: "",
8511
- configured: false
8512
- };
8513
- })
8514
- };
8515
- });
8516
- });
8517
- __publicField$1(this, "onHeaderRemove", (headerId) => {
8518
- this.setState(
8519
- ({ headers }) => ({
8520
- headers: headers.filter((h) => h.id !== headerId)
8521
- }),
8522
- this.updateSettings
8523
- );
8524
- });
8525
- const { jsonData, secureJsonData, secureJsonFields } = this.props.dataSourceConfig;
8526
- this.state = {
8527
- headers: Object.keys(jsonData).sort().filter((key) => key.startsWith("httpHeaderName")).map((key, index) => {
8528
- return {
8529
- id: lodash.uniqueId(),
8530
- name: jsonData[key],
8531
- value: secureJsonData !== void 0 ? secureJsonData[key] : "",
8532
- configured: secureJsonFields && secureJsonFields[`httpHeaderValue${index + 1}`] || false
8533
- };
8534
- })
8535
- };
8478
+ }
8536
8479
  }
8537
- render() {
8538
- const { headers } = this.state;
8539
- return /* @__PURE__ */ React__default.default.createElement("div", { className: "gf-form-group" }, /* @__PURE__ */ React__default.default.createElement("div", { className: "gf-form" }, /* @__PURE__ */ React__default.default.createElement("h6", null, "Custom HTTP Headers")), /* @__PURE__ */ React__default.default.createElement("div", null, headers.map((header, i) => /* @__PURE__ */ React__default.default.createElement(
8540
- CustomHeaderRow,
8541
- {
8542
- key: header.id,
8543
- header,
8544
- onChange: (h) => {
8545
- this.onHeaderChange(i, h);
8546
- },
8547
- onBlur: this.updateSettings,
8548
- onRemove: this.onHeaderRemove,
8549
- onReset: this.onHeaderReset
8480
+ if (requiredIds.size === 0) {
8481
+ return null;
8482
+ }
8483
+ const includeIds = /* @__PURE__ */ new Set();
8484
+ for (const id of requiredIds) {
8485
+ includeIds.add(id);
8486
+ const f = fieldMap.get(id);
8487
+ if (f == null ? void 0 : f.dependsOn) {
8488
+ const parsed = parseDependsOn(f.dependsOn);
8489
+ if (parsed && fieldMap.has(parsed.field)) {
8490
+ includeIds.add(parsed.field);
8550
8491
  }
8551
- ))), /* @__PURE__ */ React__default.default.createElement("div", { className: "gf-form" }, /* @__PURE__ */ React__default.default.createElement(
8552
- ui.Button,
8553
- {
8554
- variant: "secondary",
8555
- icon: "plus",
8556
- type: "button",
8557
- onClick: (e) => {
8558
- this.onHeaderAdd();
8559
- }
8560
- },
8561
- "Add header"
8562
- )));
8492
+ }
8563
8493
  }
8564
- }
8565
-
8566
- var QueryEditorMode = /* @__PURE__ */ ((QueryEditorMode2) => {
8567
- QueryEditorMode2["Code"] = "code";
8568
- QueryEditorMode2["Builder"] = "builder";
8569
- return QueryEditorMode2;
8570
- })(QueryEditorMode || {});
8571
- const BINARY_OPERATIONS_KEY = "Binary operations";
8572
-
8573
- var __defProp = Object.defineProperty;
8574
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8575
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
8576
- class QueryModellerBase {
8577
- constructor(operationDefinitions, innerQueryPlaceholder) {
8578
- __publicField(this, "operationsRegistry");
8579
- __publicField(this, "categories", []);
8580
- __publicField(this, "innerQueryPlaceholder");
8581
- this.operationsRegistry = new data.Registry(() => operationDefinitions);
8582
- this.innerQueryPlaceholder = innerQueryPlaceholder || "<query>";
8494
+ for (const f of schema.fields) {
8495
+ if (f.dependsOn && !includeIds.has(f.id)) {
8496
+ const parsed = parseDependsOn(f.dependsOn);
8497
+ if (parsed && requiredIds.has(parsed.field)) {
8498
+ includeIds.add(f.id);
8499
+ }
8500
+ }
8583
8501
  }
8584
- setOperationCategories(categories) {
8585
- this.categories = categories;
8502
+ const virtualFields = schema.fields.filter((f) => includeIds.has(f.id));
8503
+ if (virtualFields.length === 0) {
8504
+ return null;
8586
8505
  }
8587
- getOperationsForCategory(category) {
8588
- return this.operationsRegistry.list().filter((op) => op.category === category && !op.hideFromList);
8506
+ return {
8507
+ group: {
8508
+ id: "_required",
8509
+ title: "Required",
8510
+ fieldRefs: virtualFields.map((f) => f.id)
8511
+ },
8512
+ fields: virtualFields
8513
+ };
8514
+ }
8515
+ function formKey(field) {
8516
+ return field.section ? `${field.section}.${field.key}` : field.key;
8517
+ }
8518
+ function parseDependsOn(expr) {
8519
+ var _a, _b;
8520
+ const m = expr.match(/^(.+?)\s*==\s*(?:'([^']*)'|"([^"]*)"|(.+))$/);
8521
+ if (!m) {
8522
+ return null;
8589
8523
  }
8590
- getAlternativeOperations(key) {
8591
- return this.operationsRegistry.list().filter((op) => op.alternativesKey && op.alternativesKey === key);
8524
+ return { field: m[1].trim(), value: ((_b = (_a = m[2]) != null ? _a : m[3]) != null ? _b : m[4]).trim() };
8525
+ }
8526
+ function resolveActiveOverride(field, watchedValues, fieldById) {
8527
+ var _a;
8528
+ if (!field.overrides || field.overrides.length === 0) {
8529
+ return void 0;
8592
8530
  }
8593
- getCategories() {
8594
- return this.categories;
8531
+ for (const ov of field.overrides) {
8532
+ const parsed = parseDependsOn(ov.when);
8533
+ if (!parsed) {
8534
+ continue;
8535
+ }
8536
+ const depField = fieldById.get(parsed.field);
8537
+ const depKey = depField ? formKey(depField) : parsed.field;
8538
+ if (String((_a = watchedValues[depKey]) != null ? _a : "") === parsed.value) {
8539
+ return ov;
8540
+ }
8595
8541
  }
8596
- getOperationDefinition(id) {
8597
- return this.operationsRegistry.getIfExists(id);
8542
+ return void 0;
8543
+ }
8544
+ function resolveFieldValue(ref, values, fields) {
8545
+ if (ref in values) {
8546
+ return values[ref];
8598
8547
  }
8599
- hasBinaryOp(query) {
8600
- return query.operations.find((op) => {
8601
- const def = this.getOperationDefinition(op.id);
8602
- return (def == null ? void 0 : def.category) === BINARY_OPERATIONS_KEY;
8603
- }) !== void 0;
8548
+ const field = fields.find((f) => f.id === ref);
8549
+ if (field) {
8550
+ const fk = formKey(field);
8551
+ if (fk in values) {
8552
+ return values[fk];
8553
+ }
8604
8554
  }
8555
+ return void 0;
8605
8556
  }
8606
-
8607
- const CONFLICTING_LABEL_FILTER_ERROR_MESSAGE = "You have conflicting label filters";
8608
- function LabelFilterItem({
8609
- item,
8610
- items,
8611
- defaultOp,
8612
- onChange,
8613
- onDelete,
8614
- onGetLabelNames,
8557
+ function evaluateComputedRead(expr, values, fields) {
8558
+ function evalExpr(s) {
8559
+ var _a;
8560
+ s = s.trim();
8561
+ if (s.startsWith("(") && findMatchingParen(s, 0) === s.length - 1) {
8562
+ s = s.slice(1, -1).trim();
8563
+ }
8564
+ const qIdx = findTopLevel(s, "?");
8565
+ if (qIdx !== -1) {
8566
+ const condition = s.slice(0, qIdx).trim();
8567
+ const rest = s.slice(qIdx + 1);
8568
+ const cIdx = findTopLevel(rest, ":");
8569
+ if (cIdx !== -1) {
8570
+ const trueExpr = rest.slice(0, cIdx).trim();
8571
+ const falseExpr = rest.slice(cIdx + 1).trim();
8572
+ return evalCondition(condition) ? evalExpr(trueExpr) : evalExpr(falseExpr);
8573
+ }
8574
+ }
8575
+ const strMatch = (_a = s.match(/^'([^']*)'$/)) != null ? _a : s.match(/^"([^"]*)"$/);
8576
+ if (strMatch) {
8577
+ return strMatch[1];
8578
+ }
8579
+ if (s === "true") {
8580
+ return true;
8581
+ }
8582
+ if (s === "false") {
8583
+ return false;
8584
+ }
8585
+ if (/^-?\d+(\.\d+)?$/.test(s)) {
8586
+ return Number(s);
8587
+ }
8588
+ return resolveFieldValue(s, values, fields);
8589
+ }
8590
+ function evalCondition(cond) {
8591
+ const eqMatch = cond.match(/^(.+?)\s*(==|!=)\s*(.+)$/);
8592
+ if (eqMatch) {
8593
+ const left = evalExpr(eqMatch[1]);
8594
+ const right = evalExpr(eqMatch[3]);
8595
+ const eq = String(left) === String(right);
8596
+ return eqMatch[2] === "==" ? eq : !eq;
8597
+ }
8598
+ return !!evalExpr(cond);
8599
+ }
8600
+ function findMatchingParen(s, start) {
8601
+ let depth = 0;
8602
+ for (let i = start; i < s.length; i++) {
8603
+ if (s[i] === "(") {
8604
+ depth++;
8605
+ } else if (s[i] === ")") {
8606
+ depth--;
8607
+ if (depth === 0) {
8608
+ return i;
8609
+ }
8610
+ }
8611
+ }
8612
+ return -1;
8613
+ }
8614
+ function findTopLevel(s, char) {
8615
+ let depth = 0;
8616
+ let inStr = null;
8617
+ for (let i = 0; i < s.length; i++) {
8618
+ const c = s[i];
8619
+ if (inStr) {
8620
+ if (c === inStr) {
8621
+ inStr = null;
8622
+ }
8623
+ continue;
8624
+ }
8625
+ if (c === "'" || c === '"') {
8626
+ inStr = c;
8627
+ continue;
8628
+ }
8629
+ if (c === "(") {
8630
+ depth++;
8631
+ continue;
8632
+ }
8633
+ if (c === ")") {
8634
+ depth--;
8635
+ continue;
8636
+ }
8637
+ if (depth === 0 && c === char) {
8638
+ return i;
8639
+ }
8640
+ }
8641
+ return -1;
8642
+ }
8643
+ try {
8644
+ return evalExpr(expr);
8645
+ } catch (e) {
8646
+ return void 0;
8647
+ }
8648
+ }
8649
+ function computeVirtualFieldValues(schema, existingValues) {
8650
+ var _a;
8651
+ const virtualValues = {};
8652
+ for (const field of schema.fields) {
8653
+ if (field.kind !== "virtual") {
8654
+ continue;
8655
+ }
8656
+ const fk = formKey(field);
8657
+ if (((_a = field.storage) == null ? void 0 : _a.type) === "computed" && field.storage.read) {
8658
+ const val = evaluateComputedRead(field.storage.read, existingValues, schema.fields);
8659
+ if (val !== void 0) {
8660
+ virtualValues[fk] = val;
8661
+ } else if (field.defaultValue !== void 0) {
8662
+ virtualValues[fk] = field.defaultValue;
8663
+ }
8664
+ } else if (field.defaultValue !== void 0) {
8665
+ virtualValues[fk] = field.defaultValue;
8666
+ }
8667
+ }
8668
+ return virtualValues;
8669
+ }
8670
+
8671
+ const SECURE_FIELD_CONFIGURED = "__CONFIGURED__";
8672
+ function patternToRegex(pattern) {
8673
+ const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8674
+ return new RegExp("^" + escaped.replace("\\{index\\}", "(\\d+)") + "$");
8675
+ }
8676
+ function findIndicesForPattern(record, pattern) {
8677
+ const re = patternToRegex(pattern);
8678
+ const indices = [];
8679
+ for (const key of Object.keys(record)) {
8680
+ const m = key.match(re);
8681
+ if (m) {
8682
+ const n = Number(m[1]);
8683
+ if (!Number.isNaN(n)) {
8684
+ indices.push(n);
8685
+ }
8686
+ }
8687
+ }
8688
+ return indices.sort((a, b) => a - b);
8689
+ }
8690
+ function expandIndexedPair(field, ds) {
8691
+ var _a, _b, _c;
8692
+ const storage = field.storage;
8693
+ if ((storage == null ? void 0 : storage.type) !== "indexedPair" || !storage.key || !storage.value) {
8694
+ return [];
8695
+ }
8696
+ const source = storage.key.target === "jsonData" ? (_a = ds.jsonData) != null ? _a : {} : ds;
8697
+ const indices = findIndicesForPattern(source, storage.key.pattern);
8698
+ const items = [];
8699
+ for (const i of indices) {
8700
+ const nameKey = storage.key.pattern.replace("{index}", String(i));
8701
+ const valueKey = storage.value.pattern.replace("{index}", String(i));
8702
+ const nameVal = source[nameKey];
8703
+ if (nameVal === void 0 || nameVal === null) {
8704
+ continue;
8705
+ }
8706
+ const hasValue = storage.value.target === "secureJsonData" ? !!((_b = ds.secureJsonFields) == null ? void 0 : _b[valueKey]) : !!((_c = ds.jsonData) == null ? void 0 : _c[valueKey]);
8707
+ items.push({
8708
+ index: i,
8709
+ name: String(nameVal),
8710
+ value: hasValue ? SECURE_FIELD_CONFIGURED : ""
8711
+ });
8712
+ }
8713
+ return items;
8714
+ }
8715
+ function flattenIndexedPair(field, items, jsonData, secureJsonData, secureJsonFields) {
8716
+ var _a;
8717
+ const storage = field.storage;
8718
+ if ((storage == null ? void 0 : storage.type) !== "indexedPair" || !storage.key || !storage.value) {
8719
+ return;
8720
+ }
8721
+ const existingIndices = new Set(
8722
+ storage.key.target === "jsonData" ? findIndicesForPattern(jsonData, storage.key.pattern) : []
8723
+ );
8724
+ const usedIndices = /* @__PURE__ */ new Set();
8725
+ const startIdx = (_a = storage.startIndex) != null ? _a : 1;
8726
+ let nextIndex = existingIndices.size > 0 ? Math.max(...existingIndices) + 1 : startIdx;
8727
+ for (const item of items) {
8728
+ let idx = item.index;
8729
+ if (idx === 0) {
8730
+ idx = nextIndex++;
8731
+ }
8732
+ usedIndices.add(idx);
8733
+ const nameKey = storage.key.pattern.replace("{index}", String(idx));
8734
+ const valueKey = storage.value.pattern.replace("{index}", String(idx));
8735
+ if (storage.key.target === "jsonData") {
8736
+ jsonData[nameKey] = item.name;
8737
+ }
8738
+ if (storage.value.target === "secureJsonData") {
8739
+ if (item.value === SECURE_FIELD_CONFIGURED) {
8740
+ secureJsonFields[valueKey] = true;
8741
+ } else if (item.value) {
8742
+ secureJsonData[valueKey] = item.value;
8743
+ secureJsonFields[valueKey] = false;
8744
+ }
8745
+ } else if (storage.value.target === "jsonData") {
8746
+ jsonData[valueKey] = item.value;
8747
+ }
8748
+ }
8749
+ for (const idx of existingIndices) {
8750
+ if (usedIndices.has(idx)) {
8751
+ continue;
8752
+ }
8753
+ const nameKey = storage.key.pattern.replace("{index}", String(idx));
8754
+ const valueKey = storage.value.pattern.replace("{index}", String(idx));
8755
+ if (storage.key.target === "jsonData") {
8756
+ delete jsonData[nameKey];
8757
+ }
8758
+ if (storage.value.target === "secureJsonData") {
8759
+ delete secureJsonFields[valueKey];
8760
+ delete secureJsonData[valueKey];
8761
+ } else if (storage.value.target === "jsonData") {
8762
+ delete jsonData[valueKey];
8763
+ }
8764
+ }
8765
+ }
8766
+ function resolveRawPath(ref, ds) {
8767
+ var _a;
8768
+ const trimmed = ref.trim();
8769
+ if (trimmed.startsWith("jsonData.")) {
8770
+ return (_a = ds.jsonData) == null ? void 0 : _a[trimmed.slice(9)];
8771
+ }
8772
+ if (trimmed.startsWith("root.")) {
8773
+ return ds[trimmed.slice(5)];
8774
+ }
8775
+ return void 0;
8776
+ }
8777
+ async function fetchExistingValues(dsUid, fields) {
8778
+ var _a, _b, _c, _d, _e;
8779
+ try {
8780
+ const ds = await runtime.getBackendSrv().get(`/api/datasources/uid/${dsUid}`, void 0, void 0, {
8781
+ showErrorAlert: false
8782
+ });
8783
+ const values = {};
8784
+ for (const field of fields) {
8785
+ if (((_a = field.storage) == null ? void 0 : _a.type) === "indexedPair") {
8786
+ values[field.key] = expandIndexedPair(field, ds);
8787
+ continue;
8788
+ }
8789
+ const fk = formKey(field);
8790
+ switch (field.target) {
8791
+ case "root":
8792
+ if (ds[field.key] !== void 0) {
8793
+ values[fk] = ds[field.key];
8794
+ }
8795
+ break;
8796
+ case "jsonData":
8797
+ if (field.section) {
8798
+ const sectionObj = (_b = ds.jsonData) == null ? void 0 : _b[field.section];
8799
+ if ((sectionObj == null ? void 0 : sectionObj[field.key]) !== void 0) {
8800
+ values[fk] = sectionObj[field.key];
8801
+ }
8802
+ } else if (((_c = ds.jsonData) == null ? void 0 : _c[field.key]) !== void 0) {
8803
+ values[fk] = ds.jsonData[field.key];
8804
+ }
8805
+ break;
8806
+ case "secureJsonData":
8807
+ if ((_d = ds.secureJsonFields) == null ? void 0 : _d[field.key]) {
8808
+ values[fk] = SECURE_FIELD_CONFIGURED;
8809
+ }
8810
+ break;
8811
+ }
8812
+ if (values[fk] === void 0 && ((_e = field.storage) == null ? void 0 : _e.type) === "computed" && field.storage.read) {
8813
+ const fallback = resolveRawPath(field.storage.read, ds);
8814
+ if (fallback !== void 0) {
8815
+ values[fk] = fallback;
8816
+ }
8817
+ }
8818
+ }
8819
+ return { values, readOnly: !!ds.readOnly };
8820
+ } catch (err) {
8821
+ const message = err instanceof Error ? err.message : "Failed to load datasource configuration";
8822
+ return { values: {}, readOnly: false, error: message };
8823
+ }
8824
+ }
8825
+ function buildDatasourceConfigPayload(data, fields, existing, isFieldVisible) {
8826
+ var _a, _b, _c, _d;
8827
+ const rootFields = {};
8828
+ const jsonData = { ...(_a = existing.jsonData) != null ? _a : {} };
8829
+ const secureJsonData = {};
8830
+ const secureJsonFields = { ...(_b = existing.secureJsonFields) != null ? _b : {} };
8831
+ for (const field of fields) {
8832
+ if (((_c = field.storage) == null ? void 0 : _c.type) === "indexedPair") {
8833
+ const items = Array.isArray(data[field.key]) ? data[field.key] : [];
8834
+ flattenIndexedPair(field, items, jsonData, secureJsonData, secureJsonFields);
8835
+ continue;
8836
+ }
8837
+ const isManagedByEffect = (_d = field.tags) == null ? void 0 : _d.some((t) => t.startsWith("managed-by:"));
8838
+ if (!isManagedByEffect && !isFieldVisible(field)) {
8839
+ continue;
8840
+ }
8841
+ const fk = formKey(field);
8842
+ const value = data[fk];
8843
+ if (field.target === "secureJsonData") {
8844
+ if (value === SECURE_FIELD_CONFIGURED) {
8845
+ secureJsonFields[field.key] = true;
8846
+ continue;
8847
+ }
8848
+ if (value && value !== "") {
8849
+ secureJsonData[field.key] = String(value);
8850
+ secureJsonFields[field.key] = false;
8851
+ } else {
8852
+ secureJsonFields[field.key] = false;
8853
+ }
8854
+ continue;
8855
+ }
8856
+ if (value === void 0 || value === "") {
8857
+ continue;
8858
+ }
8859
+ switch (field.target) {
8860
+ case "root":
8861
+ rootFields[field.key] = value;
8862
+ break;
8863
+ case "jsonData":
8864
+ if (field.section) {
8865
+ if (!jsonData[field.section] || typeof jsonData[field.section] !== "object") {
8866
+ jsonData[field.section] = {};
8867
+ }
8868
+ jsonData[field.section][field.key] = value;
8869
+ } else {
8870
+ jsonData[field.key] = value;
8871
+ }
8872
+ break;
8873
+ }
8874
+ }
8875
+ return { rootFields, jsonData, secureJsonData, secureJsonFields };
8876
+ }
8877
+ async function submitDatasourceConfig(dsUid, data, fields, isFieldVisible) {
8878
+ const existing = await runtime.getBackendSrv().get(`/api/datasources/uid/${dsUid}`);
8879
+ const { rootFields, jsonData, secureJsonData, secureJsonFields } = buildDatasourceConfigPayload(
8880
+ data,
8881
+ fields,
8882
+ existing,
8883
+ isFieldVisible
8884
+ );
8885
+ await runtime.getBackendSrv().put(`/api/datasources/uid/${dsUid}`, {
8886
+ ...existing,
8887
+ ...rootFields,
8888
+ jsonData,
8889
+ secureJsonData,
8890
+ secureJsonFields
8891
+ });
8892
+ }
8893
+
8894
+ function evaluateEffectCondition(when, fieldValue) {
8895
+ var _a, _b;
8896
+ const m = when.match(/^value\s*(==|!=)\s*(?:'([^']*)'|"([^"]*)"|(.+))$/);
8897
+ if (!m) {
8898
+ return false;
8899
+ }
8900
+ const op = m[1];
8901
+ let target = (_b = (_a = m[2]) != null ? _a : m[3]) != null ? _b : m[4];
8902
+ if (target === "true") {
8903
+ target = true;
8904
+ } else if (target === "false") {
8905
+ target = false;
8906
+ } else if (typeof target === "string" && /^-?\d+(\.\d+)?$/.test(target)) {
8907
+ target = Number(target);
8908
+ }
8909
+ const eq = String(fieldValue) === String(target);
8910
+ return op === "==" ? eq : !eq;
8911
+ }
8912
+ function isFieldRequired(field, watchedValues, fieldById) {
8913
+ var _a;
8914
+ if (field.required) {
8915
+ return true;
8916
+ }
8917
+ if (field.requiredWhen) {
8918
+ const parsed = parseDependsOn(field.requiredWhen);
8919
+ if (parsed) {
8920
+ const depField = fieldById.get(parsed.field);
8921
+ const depKey = depField ? formKey(depField) : parsed.field;
8922
+ return String((_a = watchedValues[depKey]) != null ? _a : "") === parsed.value;
8923
+ }
8924
+ }
8925
+ return false;
8926
+ }
8927
+ function buildValidationRules(field, required) {
8928
+ var _a, _b, _c, _d, _e, _f;
8929
+ const rules = {};
8930
+ const label = (_a = field.label) != null ? _a : field.key;
8931
+ if (required) {
8932
+ if (field.target === "secureJsonData") {
8933
+ rules.validate = (value) => {
8934
+ if (value === SECURE_FIELD_CONFIGURED) {
8935
+ return true;
8936
+ }
8937
+ if (!value || value === "") {
8938
+ return `${label} is required`;
8939
+ }
8940
+ return true;
8941
+ };
8942
+ } else {
8943
+ rules.required = `${label} is required`;
8944
+ }
8945
+ }
8946
+ if (field.validations) {
8947
+ for (const v of field.validations) {
8948
+ switch (v.type) {
8949
+ case "pattern":
8950
+ rules.pattern = {
8951
+ value: new RegExp(v.pattern),
8952
+ message: (_b = v.message) != null ? _b : `Invalid ${label}`
8953
+ };
8954
+ break;
8955
+ case "range":
8956
+ if (v.min !== void 0) {
8957
+ rules.min = { value: v.min, message: (_c = v.message) != null ? _c : `Minimum value is ${v.min}` };
8958
+ }
8959
+ if (v.max !== void 0) {
8960
+ rules.max = { value: v.max, message: (_d = v.message) != null ? _d : `Maximum value is ${v.max}` };
8961
+ }
8962
+ break;
8963
+ case "length":
8964
+ if (v.min !== void 0) {
8965
+ rules.minLength = { value: v.min, message: (_e = v.message) != null ? _e : `Minimum length is ${v.min}` };
8966
+ }
8967
+ if (v.max !== void 0) {
8968
+ rules.maxLength = { value: v.max, message: (_f = v.message) != null ? _f : `Maximum length is ${v.max}` };
8969
+ }
8970
+ break;
8971
+ }
8972
+ }
8973
+ }
8974
+ return rules;
8975
+ }
8976
+
8977
+ function PdcFieldNote({
8978
+ enabled,
8979
+ description,
8980
+ configUrl
8981
+ }) {
8982
+ const styles = ui.useStyles2(getStyles$f);
8983
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.wrapper }, /* @__PURE__ */ React__default.default.createElement("div", { className: styles.note }, /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "shield", size: "xs" }), /* @__PURE__ */ React__default.default.createElement("span", null, "Private data source connect: ", /* @__PURE__ */ React__default.default.createElement("strong", null, enabled ? "Enabled" : "Disabled")), description && /* @__PURE__ */ React__default.default.createElement(ui.Tooltip, { content: description }, /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "info-circle", size: "xs" }))), /* @__PURE__ */ React__default.default.createElement(ui.LinkButton, { variant: "secondary", size: "sm", icon: "external-link-alt", href: configUrl }, "Configure in settings"));
8984
+ }
8985
+ const getStyles$f = (theme) => ({
8986
+ wrapper: css.css({
8987
+ display: "flex",
8988
+ alignItems: "center",
8989
+ justifyContent: "space-between",
8990
+ gap: theme.spacing(1),
8991
+ padding: `${theme.spacing(0.5)} ${theme.spacing(0.75)}`,
8992
+ fontSize: theme.typography.bodySmall.fontSize,
8993
+ color: theme.colors.text.secondary,
8994
+ backgroundColor: theme.colors.background.secondary,
8995
+ borderRadius: theme.shape.radius.default,
8996
+ border: `1px solid ${theme.colors.border.weak}`
8997
+ }),
8998
+ note: css.css({
8999
+ display: "inline-flex",
9000
+ alignItems: "center",
9001
+ gap: theme.spacing(0.5)
9002
+ })
9003
+ });
9004
+
9005
+ function SecureFieldInput({
9006
+ formField,
9007
+ placeholder,
9008
+ disabled,
9009
+ label
9010
+ }) {
9011
+ var _a;
9012
+ const isConfigured = formField.value === SECURE_FIELD_CONFIGURED;
9013
+ const [revealed, setRevealed] = React.useState(false);
9014
+ const styles = ui.useStyles2(getSecureFieldStyles);
9015
+ if (isConfigured) {
9016
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.configuredRow }, /* @__PURE__ */ React__default.default.createElement("span", { className: styles.configuredBadge }, /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "lock", size: "xs" }), label, " configured"), !disabled && /* @__PURE__ */ React__default.default.createElement(ui.Button, { variant: "secondary", fill: "text", size: "sm", onClick: () => formField.onChange(""), type: "button" }, "Reset"));
9017
+ }
9018
+ return /* @__PURE__ */ React__default.default.createElement(
9019
+ ui.Input,
9020
+ {
9021
+ ...formField,
9022
+ value: String((_a = formField.value) != null ? _a : ""),
9023
+ type: revealed ? "text" : "password",
9024
+ placeholder,
9025
+ disabled,
9026
+ suffix: /* @__PURE__ */ React__default.default.createElement(
9027
+ ui.Button,
9028
+ {
9029
+ variant: "secondary",
9030
+ fill: "text",
9031
+ size: "sm",
9032
+ icon: revealed ? "eye-slash" : "eye",
9033
+ "aria-label": revealed ? "Hide" : "Reveal",
9034
+ onClick: () => setRevealed((r) => !r),
9035
+ type: "button"
9036
+ }
9037
+ )
9038
+ }
9039
+ );
9040
+ }
9041
+ const getSecureFieldStyles = (theme) => ({
9042
+ configuredRow: css.css({
9043
+ display: "flex",
9044
+ alignItems: "center",
9045
+ gap: theme.spacing(1)
9046
+ }),
9047
+ configuredBadge: css.css({
9048
+ display: "inline-flex",
9049
+ alignItems: "center",
9050
+ gap: theme.spacing(0.5),
9051
+ padding: `${theme.spacing(0.25)} ${theme.spacing(0.75)}`,
9052
+ borderRadius: theme.shape.radius.pill,
9053
+ backgroundColor: theme.colors.success.transparent,
9054
+ color: theme.colors.success.text,
9055
+ fontSize: theme.typography.bodySmall.fontSize
9056
+ })
9057
+ });
9058
+
9059
+ function StringArrayInput({
9060
+ value,
9061
+ onChange,
9062
+ placeholder,
9063
+ disabled
9064
+ }) {
9065
+ const [draft, setDraft] = React.useState("");
9066
+ const styles = ui.useStyles2(getStyles$e);
9067
+ const addTag = () => {
9068
+ const trimmed = draft.trim();
9069
+ if (trimmed && !value.includes(trimmed)) {
9070
+ onChange([...value, trimmed]);
9071
+ }
9072
+ setDraft("");
9073
+ };
9074
+ const removeTag = (tag) => {
9075
+ onChange(value.filter((v) => v !== tag));
9076
+ };
9077
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.container }, value.length > 0 && /* @__PURE__ */ React__default.default.createElement("div", { className: styles.tags }, value.map((tag) => /* @__PURE__ */ React__default.default.createElement("span", { key: tag, className: styles.tag }, tag, !disabled && /* @__PURE__ */ React__default.default.createElement(
9078
+ "button",
9079
+ {
9080
+ type: "button",
9081
+ className: styles.tagRemove,
9082
+ onClick: () => removeTag(tag),
9083
+ "aria-label": `Remove ${tag}`
9084
+ },
9085
+ /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "times", size: "xs" })
9086
+ )))), /* @__PURE__ */ React__default.default.createElement(
9087
+ ui.Input,
9088
+ {
9089
+ value: draft,
9090
+ onChange: (e) => setDraft(e.currentTarget.value),
9091
+ onKeyDown: (e) => {
9092
+ if (e.key === "Enter") {
9093
+ e.preventDefault();
9094
+ addTag();
9095
+ }
9096
+ },
9097
+ onBlur: addTag,
9098
+ placeholder,
9099
+ disabled
9100
+ }
9101
+ ));
9102
+ }
9103
+ const getStyles$e = (theme) => ({
9104
+ container: css.css({
9105
+ display: "flex",
9106
+ flexDirection: "column",
9107
+ gap: theme.spacing(0.5)
9108
+ }),
9109
+ tags: css.css({
9110
+ display: "flex",
9111
+ flexWrap: "wrap",
9112
+ gap: theme.spacing(0.5)
9113
+ }),
9114
+ tag: css.css({
9115
+ display: "inline-flex",
9116
+ alignItems: "center",
9117
+ gap: theme.spacing(0.25),
9118
+ padding: `${theme.spacing(0.25)} ${theme.spacing(0.75)}`,
9119
+ borderRadius: theme.shape.radius.pill,
9120
+ backgroundColor: theme.colors.background.secondary,
9121
+ border: `1px solid ${theme.colors.border.weak}`,
9122
+ fontSize: theme.typography.bodySmall.fontSize,
9123
+ color: theme.colors.text.primary
9124
+ }),
9125
+ tagRemove: css.css({
9126
+ display: "inline-flex",
9127
+ alignItems: "center",
9128
+ padding: 0,
9129
+ border: "none",
9130
+ backgroundColor: "transparent",
9131
+ cursor: "pointer",
9132
+ color: theme.colors.text.secondary,
9133
+ "&:hover": { color: theme.colors.text.primary }
9134
+ })
9135
+ });
9136
+
9137
+ function IndexedPairRow({
9138
+ item,
9139
+ index,
9140
+ disabled,
9141
+ onUpdate,
9142
+ onRemove,
9143
+ hideControls
9144
+ }) {
9145
+ const styles = ui.useStyles2(getStyles$d);
9146
+ const secureStyles = ui.useStyles2(getSecureFieldStyles);
9147
+ const isConfigured = item.value === SECURE_FIELD_CONFIGURED;
9148
+ const [editing, setEditing] = React.useState(false);
9149
+ const [revealed, setRevealed] = React.useState(false);
9150
+ return /* @__PURE__ */ React__default.default.createElement(ui.Stack, { direction: "row", gap: 1 }, /* @__PURE__ */ React__default.default.createElement("div", { className: styles.inputCell }, /* @__PURE__ */ React__default.default.createElement(
9151
+ ui.Input,
9152
+ {
9153
+ value: item.name,
9154
+ placeholder: "Header name",
9155
+ disabled: disabled || hideControls,
9156
+ onChange: (e) => onUpdate(index, "name", e.currentTarget.value)
9157
+ }
9158
+ )), /* @__PURE__ */ React__default.default.createElement("div", { className: styles.inputCell }, isConfigured && !editing ? /* @__PURE__ */ React__default.default.createElement(ui.Stack, { direction: "row", gap: 1, alignItems: "center" }, /* @__PURE__ */ React__default.default.createElement("span", { className: secureStyles.configuredBadge }, /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "lock", size: "xs" }), "Configured"), !disabled && /* @__PURE__ */ React__default.default.createElement(
9159
+ ui.Button,
9160
+ {
9161
+ variant: "secondary",
9162
+ fill: "text",
9163
+ size: "sm",
9164
+ onClick: () => {
9165
+ setEditing(true);
9166
+ onUpdate(index, "value", "");
9167
+ },
9168
+ type: "button"
9169
+ },
9170
+ "Reset"
9171
+ )) : /* @__PURE__ */ React__default.default.createElement(
9172
+ ui.Input,
9173
+ {
9174
+ value: item.value === SECURE_FIELD_CONFIGURED ? "" : item.value,
9175
+ placeholder: "Header value",
9176
+ disabled,
9177
+ type: revealed ? "text" : "password",
9178
+ onChange: (e) => onUpdate(index, "value", e.currentTarget.value),
9179
+ suffix: /* @__PURE__ */ React__default.default.createElement(
9180
+ ui.Button,
9181
+ {
9182
+ variant: "secondary",
9183
+ fill: "text",
9184
+ size: "sm",
9185
+ icon: revealed ? "eye-slash" : "eye",
9186
+ "aria-label": revealed ? "Hide" : "Reveal",
9187
+ onClick: () => setRevealed((r) => !r),
9188
+ type: "button"
9189
+ }
9190
+ )
9191
+ }
9192
+ )), !hideControls && /* @__PURE__ */ React__default.default.createElement(ui.Tooltip, { content: "Remove header" }, /* @__PURE__ */ React__default.default.createElement(
9193
+ ui.Button,
9194
+ {
9195
+ variant: "secondary",
9196
+ fill: "text",
9197
+ size: "sm",
9198
+ icon: "trash-alt",
9199
+ "aria-label": "Remove header",
9200
+ disabled,
9201
+ onClick: () => onRemove(index),
9202
+ type: "button"
9203
+ }
9204
+ )));
9205
+ }
9206
+ function IndexedPairEditor({
9207
+ value,
9208
+ onChange,
9209
+ maxItems = 10,
9210
+ disabled,
9211
+ hideControls
9212
+ }) {
9213
+ const styles = ui.useStyles2(getStyles$d);
9214
+ const items = Array.isArray(value) ? value : [];
9215
+ const addItem = () => {
9216
+ if (items.length >= maxItems) {
9217
+ return;
9218
+ }
9219
+ onChange([...items, { index: 0, name: "", value: "" }]);
9220
+ };
9221
+ const removeItem = (index) => {
9222
+ onChange(items.filter((_, i) => i !== index));
9223
+ };
9224
+ const updateItem = (index, key, val) => {
9225
+ const updated = items.map((item, i) => i === index ? { ...item, [key]: val } : item);
9226
+ onChange(updated);
9227
+ };
9228
+ return /* @__PURE__ */ React__default.default.createElement(ui.Stack, { direction: "column", gap: 0.5 }, items.map((item, i) => /* @__PURE__ */ React__default.default.createElement(
9229
+ IndexedPairRow,
9230
+ {
9231
+ key: item.index || `new-${i}`,
9232
+ item,
9233
+ index: i,
9234
+ disabled,
9235
+ onUpdate: updateItem,
9236
+ onRemove: removeItem,
9237
+ hideControls
9238
+ }
9239
+ )), !hideControls && items.length < maxItems && /* @__PURE__ */ React__default.default.createElement("div", null, /* @__PURE__ */ React__default.default.createElement(ui.Button, { variant: "secondary", size: "sm", icon: "plus", disabled, onClick: addItem, type: "button" }, "Add header")), !hideControls && items.length >= maxItems && /* @__PURE__ */ React__default.default.createElement("span", { className: styles.limitNote }, "Maximum ", maxItems, " headers reached"));
9240
+ }
9241
+ const getStyles$d = (theme) => ({
9242
+ inputCell: css.css({
9243
+ flex: "1 1 0",
9244
+ minWidth: 0,
9245
+ overflow: "hidden"
9246
+ }),
9247
+ limitNote: css.css({
9248
+ fontSize: theme.typography.bodySmall.fontSize,
9249
+ color: theme.colors.text.secondary
9250
+ })
9251
+ });
9252
+
9253
+ function ComplexFieldNote({ count, label }) {
9254
+ const styles = ui.useStyles2(getStyles$c);
9255
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.note }, /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "info-circle", size: "xs" }), /* @__PURE__ */ React__default.default.createElement("span", null, count > 0 ? `${count} ${label.toLowerCase()} configured.` : `No ${label.toLowerCase()} configured.`, " Configure in Grafana UI."));
9256
+ }
9257
+ const getStyles$c = (theme) => ({
9258
+ note: css.css({
9259
+ display: "inline-flex",
9260
+ alignItems: "center",
9261
+ gap: theme.spacing(0.5),
9262
+ padding: `${theme.spacing(0.5)} ${theme.spacing(0.75)}`,
9263
+ fontSize: theme.typography.bodySmall.fontSize,
9264
+ color: theme.colors.text.secondary,
9265
+ backgroundColor: theme.colors.background.secondary,
9266
+ borderRadius: theme.shape.radius.default,
9267
+ border: `1px solid ${theme.colors.border.weak}`
9268
+ })
9269
+ });
9270
+
9271
+ function renderFieldInput(field, formField, disabled) {
9272
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
9273
+ const value = formField.value;
9274
+ const placeholder = (_a = field.ui) == null ? void 0 : _a.placeholder;
9275
+ const label = (_b = field.label) != null ? _b : field.key;
9276
+ if (field.target === "secureJsonData" || field.semanticType === "password" || field.semanticType === "token") {
9277
+ return /* @__PURE__ */ React__default.default.createElement(SecureFieldInput, { formField, placeholder: placeholder != null ? placeholder : label, disabled, label });
9278
+ }
9279
+ if (field.valueType === "boolean") {
9280
+ return /* @__PURE__ */ React__default.default.createElement(ui.Switch, { value: !!value, onChange: (e) => formField.onChange(e.currentTarget.checked), disabled });
9281
+ }
9282
+ if (field.valueType === "number") {
9283
+ return /* @__PURE__ */ React__default.default.createElement(
9284
+ ui.Input,
9285
+ {
9286
+ ...formField,
9287
+ value: value !== void 0 && value !== null ? Number(value) : "",
9288
+ type: "number",
9289
+ placeholder,
9290
+ disabled,
9291
+ onChange: (e) => {
9292
+ const n = e.currentTarget.valueAsNumber;
9293
+ formField.onChange(Number.isNaN(n) ? void 0 : n);
9294
+ }
9295
+ }
9296
+ );
9297
+ }
9298
+ if (((_c = field.ui) == null ? void 0 : _c.component) === "radio") {
9299
+ const options = ((_e = (_d = field.ui) == null ? void 0 : _d.options) != null ? _e : []).map((opt) => ({
9300
+ label: opt.label,
9301
+ value: String(opt.value),
9302
+ description: opt.description
9303
+ }));
9304
+ return /* @__PURE__ */ React__default.default.createElement("div", { style: { display: "flex" } }, /* @__PURE__ */ React__default.default.createElement(
9305
+ ui.RadioButtonGroup,
9306
+ {
9307
+ options,
9308
+ value: String(value != null ? value : ""),
9309
+ onChange: (v) => formField.onChange(v),
9310
+ disabled
9311
+ }
9312
+ ));
9313
+ }
9314
+ if (((_f = field.ui) == null ? void 0 : _f.component) === "select") {
9315
+ const options = ((_h = (_g = field.ui) == null ? void 0 : _g.options) != null ? _h : []).map((opt) => ({
9316
+ label: opt.label,
9317
+ value: String(opt.value),
9318
+ description: opt.description
9319
+ }));
9320
+ return /* @__PURE__ */ React__default.default.createElement(
9321
+ ui.Select,
9322
+ {
9323
+ options,
9324
+ value: options.find((o) => o.value === String(value != null ? value : "")),
9325
+ onChange: (v) => formField.onChange(v == null ? void 0 : v.value),
9326
+ disabled
9327
+ }
9328
+ );
9329
+ }
9330
+ if (field.semanticType === "url") {
9331
+ return /* @__PURE__ */ React__default.default.createElement(ui.Input, { ...formField, value: String(value != null ? value : ""), type: "url", placeholder, disabled });
9332
+ }
9333
+ if (((_i = field.ui) == null ? void 0 : _i.component) === "textarea") {
9334
+ return /* @__PURE__ */ React__default.default.createElement(
9335
+ ui.TextArea,
9336
+ {
9337
+ ...formField,
9338
+ value: String(value != null ? value : ""),
9339
+ placeholder,
9340
+ disabled,
9341
+ rows: (_k = (_j = field.ui) == null ? void 0 : _j.rows) != null ? _k : 3
9342
+ }
9343
+ );
9344
+ }
9345
+ if (field.valueType === "array" && ((_l = field.item) == null ? void 0 : _l.valueType) === "string") {
9346
+ return /* @__PURE__ */ React__default.default.createElement(
9347
+ StringArrayInput,
9348
+ {
9349
+ value: Array.isArray(value) ? value : [],
9350
+ onChange: formField.onChange,
9351
+ placeholder: placeholder != null ? placeholder : `Add ${label.toLowerCase()}\u2026`,
9352
+ disabled
9353
+ }
9354
+ );
9355
+ }
9356
+ if (((_m = field.storage) == null ? void 0 : _m.type) === "indexedPair") {
9357
+ const items = Array.isArray(value) ? value : [];
9358
+ const maxItems = (_p = (_o = (_n = field.validations) == null ? void 0 : _n.find((v) => v.type === "itemCount")) == null ? void 0 : _o.max) != null ? _p : 10;
9359
+ return /* @__PURE__ */ React__default.default.createElement(IndexedPairEditor, { value: items, onChange: formField.onChange, maxItems, disabled });
9360
+ }
9361
+ if (field.valueType === "object" || field.valueType === "map" || field.valueType === "array" && (((_q = field.item) == null ? void 0 : _q.valueType) === "object" || ((_r = field.item) == null ? void 0 : _r.valueType) === "map")) {
9362
+ const count = Array.isArray(value) ? value.length : 0;
9363
+ return /* @__PURE__ */ React__default.default.createElement(ComplexFieldNote, { count, label });
9364
+ }
9365
+ return /* @__PURE__ */ React__default.default.createElement(ui.Input, { ...formField, value: String(value != null ? value : ""), placeholder, disabled });
9366
+ }
9367
+
9368
+ const getWizardStyles = (theme) => ({
9369
+ container: css.css({
9370
+ position: "relative",
9371
+ display: "flex",
9372
+ flexDirection: "column",
9373
+ gap: theme.spacing(1),
9374
+ padding: theme.spacing(1.5),
9375
+ backgroundColor: theme.colors.background.secondary,
9376
+ borderRadius: theme.shape.radius.default,
9377
+ border: `1px solid ${theme.colors.border.weak}`,
9378
+ overflow: "hidden"
9379
+ }),
9380
+ overlay: css.css({
9381
+ position: "absolute",
9382
+ inset: 0,
9383
+ display: "flex",
9384
+ alignItems: "center",
9385
+ justifyContent: "center",
9386
+ gap: theme.spacing(1),
9387
+ background: theme.colors.background.secondary,
9388
+ borderRadius: theme.shape.radius.default,
9389
+ zIndex: 1,
9390
+ fontSize: theme.typography.bodySmall.fontSize,
9391
+ color: theme.colors.text.primary,
9392
+ opacity: 0.95
9393
+ }),
9394
+ readOnlyBanner: css.css({
9395
+ display: "inline-flex",
9396
+ alignItems: "center",
9397
+ gap: theme.spacing(0.5),
9398
+ padding: `${theme.spacing(0.25)} ${theme.spacing(0.75)}`,
9399
+ fontSize: theme.typography.bodySmall.fontSize,
9400
+ color: theme.colors.text.secondary,
9401
+ backgroundColor: theme.colors.background.secondary,
9402
+ borderRadius: theme.shape.radius.default,
9403
+ border: `1px solid ${theme.colors.border.weak}`
9404
+ }),
9405
+ navBar: css.css({
9406
+ display: "flex",
9407
+ alignItems: "center",
9408
+ justifyContent: "space-between"
9409
+ }),
9410
+ navTitle: css.css({
9411
+ display: "inline-flex",
9412
+ alignItems: "center",
9413
+ gap: theme.spacing(0.5),
9414
+ fontSize: theme.typography.body.fontSize,
9415
+ fontWeight: theme.typography.fontWeightBold,
9416
+ color: theme.colors.text.primary
9417
+ }),
9418
+ stepCount: css.css({
9419
+ fontSize: "11px",
9420
+ fontWeight: "normal",
9421
+ color: theme.colors.text.secondary
9422
+ }),
9423
+ navActions: css.css({
9424
+ display: "flex",
9425
+ alignItems: "center",
9426
+ gap: theme.spacing(0.25)
9427
+ }),
9428
+ form: css.css({
9429
+ display: "flex",
9430
+ flexDirection: "column",
9431
+ gap: theme.spacing(0.75)
9432
+ }),
9433
+ buttons: css.css({
9434
+ display: "flex",
9435
+ gap: theme.spacing(1),
9436
+ paddingTop: theme.spacing(0.25)
9437
+ }),
9438
+ fieldRow: css.css({
9439
+ display: "grid",
9440
+ gridTemplateColumns: "minmax(80px, 1fr) minmax(0, 2fr)",
9441
+ gap: theme.spacing(0.75),
9442
+ alignItems: "start"
9443
+ }),
9444
+ fieldRowCenter: css.css({
9445
+ display: "grid",
9446
+ gridTemplateColumns: "minmax(80px, 1fr) minmax(0, 2fr)",
9447
+ gap: theme.spacing(0.75),
9448
+ alignItems: "center",
9449
+ padding: `${theme.spacing(0.5)} 0`
9450
+ }),
9451
+ fieldLabelRow: css.css({
9452
+ display: "flex",
9453
+ alignItems: "center",
9454
+ gap: theme.spacing(0.5),
9455
+ paddingTop: theme.spacing(0.5)
9456
+ }),
9457
+ fieldLabelRowCompact: css.css({
9458
+ display: "flex",
9459
+ alignItems: "center",
9460
+ gap: theme.spacing(0.5)
9461
+ }),
9462
+ fieldLabel: css.css({
9463
+ fontSize: theme.typography.bodySmall.fontSize,
9464
+ fontWeight: theme.typography.fontWeightMedium,
9465
+ color: theme.colors.text.primary
9466
+ }),
9467
+ fieldRequired: css.css({
9468
+ color: theme.colors.error.text,
9469
+ marginLeft: 2
9470
+ }),
9471
+ fieldInfoIcon: css.css({
9472
+ color: theme.colors.text.disabled,
9473
+ cursor: "help",
9474
+ flexShrink: 0
9475
+ }),
9476
+ fieldInputCol: css.css({
9477
+ display: "flex",
9478
+ flexDirection: "column",
9479
+ gap: theme.spacing(0.25),
9480
+ minWidth: 0
9481
+ }),
9482
+ fieldError: css.css({
9483
+ fontSize: "11px",
9484
+ color: theme.colors.error.text
9485
+ })
9486
+ });
9487
+
9488
+ function SchemaField({ field, control, errors, disabled, dsUid, watchedValues, fieldById }) {
9489
+ const styles = ui.useStyles2(getWizardStyles);
9490
+ const activeOverride = resolveActiveOverride(field, watchedValues, fieldById);
9491
+ const fk = formKey(field);
9492
+ if (field.key === "pdcInjected" && field.target === "jsonData") {
9493
+ return /* @__PURE__ */ React__default.default.createElement(
9494
+ reactHookForm.Controller,
9495
+ {
9496
+ name: fk,
9497
+ control,
9498
+ render: ({ field: formField }) => /* @__PURE__ */ React__default.default.createElement(
9499
+ PdcFieldNote,
9500
+ {
9501
+ enabled: !!formField.value,
9502
+ description: field.description,
9503
+ configUrl: `/connections/datasources/edit/${dsUid}`
9504
+ }
9505
+ )
9506
+ }
9507
+ );
9508
+ }
9509
+ const required = isFieldRequired(field, watchedValues, fieldById);
9510
+ const validationRules = buildValidationRules(field, required);
9511
+ return /* @__PURE__ */ React__default.default.createElement(
9512
+ reactHookForm.Controller,
9513
+ {
9514
+ name: fk,
9515
+ control,
9516
+ rules: validationRules,
9517
+ render: ({ field: formField }) => {
9518
+ var _a, _b, _c, _d, _e;
9519
+ const errorMessage = (_a = errors[fk]) == null ? void 0 : _a.message;
9520
+ const label = (_b = field.label) != null ? _b : field.key;
9521
+ const description = (_c = activeOverride == null ? void 0 : activeOverride.description) != null ? _c : field.description;
9522
+ const effectiveField = activeOverride ? {
9523
+ ...field,
9524
+ ui: {
9525
+ ...field.ui,
9526
+ placeholder: (_e = activeOverride.placeholder) != null ? _e : (_d = field.ui) == null ? void 0 : _d.placeholder
9527
+ }
9528
+ } : field;
9529
+ const isReadOnly = !!(activeOverride == null ? void 0 : activeOverride.readOnly);
9530
+ const isBool = field.valueType === "boolean";
9531
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: isBool ? styles.fieldRowCenter : styles.fieldRow }, /* @__PURE__ */ React__default.default.createElement("div", { className: isBool ? styles.fieldLabelRowCompact : styles.fieldLabelRow }, /* @__PURE__ */ React__default.default.createElement("span", { className: styles.fieldLabel }, label, required && /* @__PURE__ */ React__default.default.createElement("span", { className: styles.fieldRequired }, "*")), description && /* @__PURE__ */ React__default.default.createElement(ui.Tooltip, { content: description }, /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "info-circle", size: "xs", className: styles.fieldInfoIcon }))), /* @__PURE__ */ React__default.default.createElement("div", { className: styles.fieldInputCol }, renderFieldInput(effectiveField, formField, disabled || isReadOnly), errorMessage && /* @__PURE__ */ React__default.default.createElement("span", { className: styles.fieldError }, errorMessage)));
9532
+ }
9533
+ }
9534
+ );
9535
+ }
9536
+
9537
+ function AuthorizationHeaderField({
9538
+ headersFieldKey,
9539
+ control,
9540
+ disabled,
9541
+ watchedValues
9542
+ }) {
9543
+ const styles = ui.useStyles2(getWizardStyles);
9544
+ const items = React.useMemo(
9545
+ () => Array.isArray(watchedValues[headersFieldKey]) ? watchedValues[headersFieldKey] : [],
9546
+ [watchedValues, headersFieldKey]
9547
+ );
9548
+ const authEntries = React.useMemo(() => {
9549
+ const entries = [];
9550
+ for (let i = 0; i < items.length; i++) {
9551
+ if (items[i].name.toLowerCase() === "authorization") {
9552
+ entries.push({ item: items[i], originalIdx: i });
9553
+ }
9554
+ }
9555
+ return entries;
9556
+ }, [items]);
9557
+ if (authEntries.length === 0) {
9558
+ return null;
9559
+ }
9560
+ const authItems = authEntries.map((e) => e.item);
9561
+ return /* @__PURE__ */ React__default.default.createElement(
9562
+ reactHookForm.Controller,
9563
+ {
9564
+ name: headersFieldKey,
9565
+ control,
9566
+ render: ({ field: formField }) => {
9567
+ const handleChange = (updatedAuthItems) => {
9568
+ const updated = [...items];
9569
+ for (let i = 0; i < authEntries.length; i++) {
9570
+ if (i < updatedAuthItems.length) {
9571
+ updated[authEntries[i].originalIdx] = updatedAuthItems[i];
9572
+ }
9573
+ }
9574
+ formField.onChange(updated);
9575
+ };
9576
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.fieldRow }, /* @__PURE__ */ React__default.default.createElement("div", { className: styles.fieldLabelRow }, /* @__PURE__ */ React__default.default.createElement("span", { className: styles.fieldLabel }, "Custom HTTP Headers"), /* @__PURE__ */ React__default.default.createElement(ui.Tooltip, { content: "Authorization HTTP header(s) sent with every request." }, /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "info-circle", size: "xs", className: styles.fieldInfoIcon }))), /* @__PURE__ */ React__default.default.createElement("div", { className: styles.fieldInputCol }, /* @__PURE__ */ React__default.default.createElement(IndexedPairEditor, { value: authItems, onChange: handleChange, disabled, hideControls: true })));
9577
+ }
9578
+ }
9579
+ );
9580
+ }
9581
+
9582
+ const getTabStyles = (theme) => ({
9583
+ root: css.css({
9584
+ display: "flex",
9585
+ gap: theme.spacing(3),
9586
+ position: "relative",
9587
+ background: theme.colors.background.canvas,
9588
+ padding: theme.spacing(2)
9589
+ }),
9590
+ // Sidebar
9591
+ sidebar: css.css({
9592
+ width: 250,
9593
+ flexShrink: 0,
9594
+ position: "sticky",
9595
+ top: theme.spacing(2),
9596
+ alignSelf: "flex-start",
9597
+ [theme.breakpoints.down("sm")]: { display: "none" }
9598
+ }),
9599
+ sidebarTitle: css.css({
9600
+ fontSize: theme.typography.body.fontSize,
9601
+ fontWeight: theme.typography.fontWeightMedium,
9602
+ color: theme.colors.text.primary,
9603
+ padding: `${theme.spacing(1)} 0`,
9604
+ marginBottom: theme.spacing(1)
9605
+ }),
9606
+ navList: css.css({
9607
+ listStyle: "none",
9608
+ margin: 0,
9609
+ padding: 0,
9610
+ position: "relative"
9611
+ }),
9612
+ navItem: css.css({
9613
+ display: "flex",
9614
+ alignItems: "flex-start",
9615
+ gap: theme.spacing(1.5),
9616
+ padding: `${theme.spacing(1)} 0`,
9617
+ cursor: "pointer",
9618
+ position: "relative"
9619
+ }),
9620
+ navItemActive: css.css({}),
9621
+ // Dot container: positions the dot and the connector line
9622
+ navDotWrap: css.css({
9623
+ position: "relative",
9624
+ display: "flex",
9625
+ alignItems: "center",
9626
+ justifyContent: "center",
9627
+ width: 12,
9628
+ flexShrink: 0,
9629
+ alignSelf: "flex-start",
9630
+ paddingTop: 4
9631
+ }),
9632
+ navDot: css.css({
9633
+ width: 10,
9634
+ height: 10,
9635
+ borderRadius: "50%",
9636
+ border: `2px solid ${theme.colors.text.disabled}`,
9637
+ background: theme.colors.background.canvas,
9638
+ position: "relative",
9639
+ zIndex: 1
9640
+ }),
9641
+ navDotOptional: css.css({
9642
+ borderStyle: "dashed"
9643
+ }),
9644
+ navDotActive: css.css({
9645
+ background: theme.colors.primary.main,
9646
+ borderColor: theme.colors.primary.main,
9647
+ borderStyle: "solid"
9648
+ }),
9649
+ navDotValidated: css.css({
9650
+ background: theme.colors.success.main,
9651
+ borderColor: theme.colors.success.main,
9652
+ borderStyle: "solid"
9653
+ }),
9654
+ navDotError: css.css({
9655
+ background: theme.colors.error.main,
9656
+ borderColor: theme.colors.error.main,
9657
+ borderStyle: "solid"
9658
+ }),
9659
+ // Connector line running from dot center downward to next item
9660
+ navConnector: css.css({
9661
+ position: "absolute",
9662
+ left: 5,
9663
+ top: 16,
9664
+ bottom: -16,
9665
+ width: 2,
9666
+ background: theme.colors.border.medium,
9667
+ zIndex: 0
9668
+ }),
9669
+ navConnectorDashed: css.css({
9670
+ background: "none",
9671
+ borderLeft: `2px dashed ${theme.colors.border.weak}`,
9672
+ width: 0
9673
+ }),
9674
+ navLabel: css.css({
9675
+ fontSize: theme.typography.body.fontSize,
9676
+ color: "rgba(204, 204, 220, 0.65)",
9677
+ lineHeight: 1.4
9678
+ }),
9679
+ navLabelActive: css.css({
9680
+ fontWeight: theme.typography.fontWeightMedium,
9681
+ color: theme.colors.text.primary
9682
+ }),
9683
+ // Main content
9684
+ main: css.css({
9685
+ flex: 1,
9686
+ minWidth: 0,
9687
+ width: 0,
9688
+ // forces flex child to respect flex-grow and fill remaining space
9689
+ display: "flex",
9690
+ flexDirection: "column",
9691
+ gap: theme.spacing(2)
9692
+ }),
9693
+ form: css.css({
9694
+ display: "flex",
9695
+ flexDirection: "column",
9696
+ gap: theme.spacing(2)
9697
+ }),
9698
+ requiredNotice: css.css({
9699
+ fontSize: theme.typography.bodySmall.fontSize,
9700
+ color: theme.colors.text.secondary,
9701
+ marginBottom: theme.spacing(0.5)
9702
+ }),
9703
+ // Section wrapper — card container around CollapsableSection
9704
+ section: css.css({
9705
+ border: `1px solid ${theme.colors.border.weak}`,
9706
+ borderRadius: theme.shape.radius.default,
9707
+ background: theme.colors.background.secondary,
9708
+ overflow: "hidden"
9709
+ }),
9710
+ // Override Collapse component styling
9711
+ collapseHeader: css.css({
9712
+ borderRadius: theme.shape.radius.default,
9713
+ background: "none",
9714
+ border: "none",
9715
+ marginBottom: 0,
9716
+ // Collapse header button: make label fill remaining space
9717
+ "& > button": {
9718
+ padding: `${theme.spacing(1.5)} ${theme.spacing(2)}`,
9719
+ width: "100%",
9720
+ justifyContent: "flex-start"
9721
+ },
9722
+ "& > button > div": {
9723
+ flex: 1,
9724
+ fontSize: theme.typography.h4.fontSize,
9725
+ fontWeight: theme.typography.fontWeightMedium,
9726
+ textAlign: "left"
9727
+ }
9728
+ }),
9729
+ sectionLabel: css.css({
9730
+ display: "flex",
9731
+ alignItems: "center",
9732
+ flex: 1
9733
+ }),
9734
+ sectionLabelText: css.css({
9735
+ flex: 1
9736
+ }),
9737
+ sectionHeader: css.css({
9738
+ display: "flex",
9739
+ alignItems: "center",
9740
+ gap: theme.spacing(1),
9741
+ padding: `${theme.spacing(1.5)} ${theme.spacing(2)}`,
9742
+ cursor: "pointer",
9743
+ userSelect: "none"
9744
+ }),
9745
+ sectionChevron: css.css({
9746
+ transition: "transform 0.2s ease"
9747
+ }),
9748
+ sectionChevronOpen: css.css({
9749
+ transform: "rotate(90deg)"
9750
+ }),
9751
+ sectionTitle: css.css({
9752
+ fontSize: theme.typography.h4.fontSize,
9753
+ fontWeight: theme.typography.fontWeightMedium,
9754
+ flex: 1,
9755
+ textAlign: "left"
9756
+ }),
9757
+ sectionBadge: css.css({
9758
+ fontSize: "11px",
9759
+ fontWeight: "normal",
9760
+ color: theme.colors.text.disabled,
9761
+ border: `1px solid ${theme.colors.border.weak}`,
9762
+ borderRadius: theme.shape.radius.pill,
9763
+ padding: `1px ${theme.spacing(0.75)}`,
9764
+ whiteSpace: "nowrap"
9765
+ }),
9766
+ sectionDescription: css.css({
9767
+ fontSize: theme.typography.bodySmall.fontSize,
9768
+ color: theme.colors.text.secondary,
9769
+ marginBottom: theme.spacing(1.5)
9770
+ }),
9771
+ sectionBody: css.css({
9772
+ padding: `0 ${theme.spacing(2)} ${theme.spacing(2)}`,
9773
+ display: "flex",
9774
+ flexDirection: "column",
9775
+ gap: theme.spacing(0.75)
9776
+ }),
9777
+ // Form bottom
9778
+ formButtons: css.css({
9779
+ display: "flex",
9780
+ gap: theme.spacing(1),
9781
+ paddingTop: theme.spacing(0.5)
9782
+ }),
9783
+ // Loading / error states
9784
+ loadingContainer: css.css({
9785
+ display: "flex",
9786
+ alignItems: "center",
9787
+ gap: theme.spacing(1),
9788
+ padding: theme.spacing(3),
9789
+ color: theme.colors.text.secondary
9790
+ }),
9791
+ overlay: css.css({
9792
+ position: "absolute",
9793
+ inset: 0,
9794
+ display: "flex",
9795
+ alignItems: "center",
9796
+ justifyContent: "center",
9797
+ gap: theme.spacing(1),
9798
+ background: theme.colors.background.secondary,
9799
+ borderRadius: theme.shape.radius.default,
9800
+ zIndex: 1,
9801
+ fontSize: theme.typography.bodySmall.fontSize,
9802
+ color: theme.colors.text.primary,
9803
+ opacity: 0.95
9804
+ }),
9805
+ readOnlyBanner: css.css({
9806
+ display: "inline-flex",
9807
+ alignItems: "center",
9808
+ gap: theme.spacing(0.5),
9809
+ padding: `${theme.spacing(0.25)} ${theme.spacing(0.75)}`,
9810
+ fontSize: theme.typography.bodySmall.fontSize,
9811
+ color: theme.colors.text.secondary,
9812
+ backgroundColor: theme.colors.background.secondary,
9813
+ borderRadius: theme.shape.radius.default,
9814
+ border: `1px solid ${theme.colors.border.weak}`,
9815
+ marginBottom: theme.spacing(1)
9816
+ })
9817
+ });
9818
+
9819
+ function SidebarNav({ groups, activeIndex, sectionStates, onSelect }) {
9820
+ const styles = ui.useStyles2(getTabStyles);
9821
+ const visibleGroups = groups.filter((g) => g.group.id !== "_required");
9822
+ return /* @__PURE__ */ React__default.default.createElement("nav", { className: styles.sidebar }, /* @__PURE__ */ React__default.default.createElement("div", { className: styles.sidebarTitle }, "Connect data source"), /* @__PURE__ */ React__default.default.createElement("ul", { className: styles.navList }, visibleGroups.map((g, vi) => {
9823
+ var _a, _b;
9824
+ const origIndex = groups.indexOf(g);
9825
+ const state = (_a = sectionStates[origIndex]) != null ? _a : "draft";
9826
+ const isActive = origIndex === activeIndex;
9827
+ const isOptional = g.group.optional === true;
9828
+ const isLast = vi === visibleGroups.length - 1;
9829
+ const nextIsOptional = !isLast && ((_b = visibleGroups[vi + 1]) == null ? void 0 : _b.group.optional) === true;
9830
+ return /* @__PURE__ */ React__default.default.createElement("li", { key: g.group.id }, /* @__PURE__ */ React__default.default.createElement(
9831
+ "div",
9832
+ {
9833
+ className: css.cx(styles.navItem, isActive && styles.navItemActive),
9834
+ onClick: () => onSelect(origIndex),
9835
+ role: "button",
9836
+ tabIndex: 0,
9837
+ onKeyDown: (e) => {
9838
+ if (e.key === "Enter" || e.key === " ") {
9839
+ e.preventDefault();
9840
+ onSelect(origIndex);
9841
+ }
9842
+ }
9843
+ },
9844
+ /* @__PURE__ */ React__default.default.createElement("div", { className: styles.navDotWrap }, /* @__PURE__ */ React__default.default.createElement(
9845
+ "span",
9846
+ {
9847
+ className: css.cx(
9848
+ styles.navDot,
9849
+ isOptional && styles.navDotOptional,
9850
+ isActive && styles.navDotActive,
9851
+ state === "validated" && !isActive && styles.navDotValidated,
9852
+ state === "error" && !isActive && styles.navDotError
9853
+ )
9854
+ }
9855
+ ), !isLast && /* @__PURE__ */ React__default.default.createElement(
9856
+ "div",
9857
+ {
9858
+ className: css.cx(styles.navConnector, (isOptional || nextIsOptional) && styles.navConnectorDashed)
9859
+ }
9860
+ )),
9861
+ /* @__PURE__ */ React__default.default.createElement("span", { className: css.cx(styles.navLabel, isActive && styles.navLabelActive) }, g.group.title)
9862
+ ));
9863
+ })));
9864
+ }
9865
+
9866
+ function TabLayout({ form, schema, dsUid, dsName, onRetest, healthError, renderActions }) {
9867
+ const styles = ui.useStyles2(getTabStyles);
9868
+ const sectionRefs = React.useRef(/* @__PURE__ */ new Map());
9869
+ const {
9870
+ resolvedGroups,
9871
+ fieldById,
9872
+ httpHeadersField,
9873
+ control,
9874
+ handleSubmit,
9875
+ errors,
9876
+ watchedValues,
9877
+ initializing,
9878
+ fetchError,
9879
+ submitting,
9880
+ submitError,
9881
+ readOnly,
9882
+ isFieldVisible,
9883
+ isGroupValid,
9884
+ groupHasData,
9885
+ onSubmit
9886
+ } = form;
9887
+ const displayGroups = React.useMemo(() => resolvedGroups.filter((g) => g.group.id !== "_required"), [resolvedGroups]);
9888
+ const [expandedSections, setExpandedSections] = React.useState(() => {
9889
+ const expanded = /* @__PURE__ */ new Set();
9890
+ for (let i = 0; i < displayGroups.length; i++) {
9891
+ if (!displayGroups[i].group.optional) {
9892
+ expanded.add(i);
9893
+ }
9894
+ }
9895
+ return expanded;
9896
+ });
9897
+ const hasExpandedForData = React.useRef(false);
9898
+ React.useMemo(() => {
9899
+ if (initializing || hasExpandedForData.current) {
9900
+ return;
9901
+ }
9902
+ hasExpandedForData.current = true;
9903
+ setExpandedSections((prev) => {
9904
+ const next = new Set(prev);
9905
+ for (let i = 0; i < displayGroups.length; i++) {
9906
+ if (groupHasData(displayGroups[i])) {
9907
+ next.add(i);
9908
+ }
9909
+ }
9910
+ return next;
9911
+ });
9912
+ }, [initializing, displayGroups, groupHasData]);
9913
+ const [activeSection, setActiveSection] = React.useState(0);
9914
+ const toggleSection = React.useCallback((index) => {
9915
+ setExpandedSections((prev) => {
9916
+ const next = new Set(prev);
9917
+ if (next.has(index)) {
9918
+ next.delete(index);
9919
+ } else {
9920
+ next.add(index);
9921
+ }
9922
+ return next;
9923
+ });
9924
+ }, []);
9925
+ const scrollToSection = React.useCallback(
9926
+ (index) => {
9927
+ setActiveSection(index);
9928
+ if (!expandedSections.has(index)) {
9929
+ setExpandedSections((prev) => new Set(prev).add(index));
9930
+ }
9931
+ const el = sectionRefs.current.get(index);
9932
+ if (el) {
9933
+ el.scrollIntoView({ behavior: "smooth", block: "start" });
9934
+ }
9935
+ },
9936
+ [expandedSections]
9937
+ );
9938
+ const sectionStates = React.useMemo(() => {
9939
+ return displayGroups.map((g, i) => {
9940
+ if (i === activeSection) {
9941
+ return "active";
9942
+ }
9943
+ if (!isGroupValid(g)) {
9944
+ return "error";
9945
+ }
9946
+ if (groupHasData(g)) {
9947
+ return "validated";
9948
+ }
9949
+ return "draft";
9950
+ });
9951
+ }, [displayGroups, activeSection, isGroupValid, groupHasData]);
9952
+ if (initializing) {
9953
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.loadingContainer }, /* @__PURE__ */ React__default.default.createElement(ui.Spinner, { size: "sm", inline: true }), " Loading configuration\u2026");
9954
+ }
9955
+ if (fetchError) {
9956
+ return /* @__PURE__ */ React__default.default.createElement("div", null, /* @__PURE__ */ React__default.default.createElement(ui.Alert, { severity: "error", title: "Failed to load configuration" }, fetchError), /* @__PURE__ */ React__default.default.createElement("div", { className: styles.formButtons }, /* @__PURE__ */ React__default.default.createElement(
9957
+ ui.LinkButton,
9958
+ {
9959
+ variant: "secondary",
9960
+ size: "sm",
9961
+ icon: "external-link-alt",
9962
+ href: `/connections/datasources/edit/${dsUid}`
9963
+ },
9964
+ "Open datasource settings"
9965
+ )));
9966
+ }
9967
+ const allDisabled = submitting || readOnly;
9968
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.root }, submitting && /* @__PURE__ */ React__default.default.createElement("div", { className: styles.overlay }, /* @__PURE__ */ React__default.default.createElement(ui.Spinner, { size: "sm" }), /* @__PURE__ */ React__default.default.createElement("span", null, "Saving & testing\u2026")), /* @__PURE__ */ React__default.default.createElement(
9969
+ SidebarNav,
9970
+ {
9971
+ groups: displayGroups,
9972
+ activeIndex: activeSection,
9973
+ sectionStates,
9974
+ onSelect: scrollToSection
9975
+ }
9976
+ ), /* @__PURE__ */ React__default.default.createElement("div", { className: styles.main }, readOnly && /* @__PURE__ */ React__default.default.createElement("div", { className: styles.readOnlyBanner }, /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "lock", size: "xs" }), /* @__PURE__ */ React__default.default.createElement("span", null, "Read-only \u2014 managed externally")), /* @__PURE__ */ React__default.default.createElement("div", { className: styles.requiredNotice }, "Fields marked with * are required"), /* @__PURE__ */ React__default.default.createElement("form", { onSubmit: handleSubmit(onSubmit), className: styles.form }, displayGroups.map((g, i) => {
9977
+ const visibleFields = g.fields.filter(isFieldVisible);
9978
+ if (visibleFields.length === 0 && !httpHeadersField) {
9979
+ return null;
9980
+ }
9981
+ const showHeaders = httpHeadersField && (g.group.id === "auth" || g.group.id === "url-and-auth" || g.group.id === "_required" || g.group.fieldRefs.includes("httpHeaders"));
9982
+ const sectionLabel = /* @__PURE__ */ React__default.default.createElement("span", { className: styles.sectionLabel }, /* @__PURE__ */ React__default.default.createElement("span", { className: styles.sectionLabelText }, g.group.title), g.group.optional && /* @__PURE__ */ React__default.default.createElement("span", { className: styles.sectionBadge }, "Optional"));
9983
+ return /* @__PURE__ */ React__default.default.createElement(
9984
+ "div",
9985
+ {
9986
+ key: g.group.id,
9987
+ ref: (el) => {
9988
+ if (el) {
9989
+ sectionRefs.current.set(i, el);
9990
+ }
9991
+ },
9992
+ className: styles.section
9993
+ },
9994
+ /* @__PURE__ */ React__default.default.createElement(
9995
+ ui.Collapse,
9996
+ {
9997
+ label: sectionLabel,
9998
+ isOpen: expandedSections.has(i),
9999
+ collapsible: true,
10000
+ onToggle: () => {
10001
+ toggleSection(i);
10002
+ setActiveSection(i);
10003
+ },
10004
+ className: styles.collapseHeader
10005
+ },
10006
+ /* @__PURE__ */ React__default.default.createElement("div", { className: styles.sectionBody }, g.group.description && /* @__PURE__ */ React__default.default.createElement("div", { className: styles.sectionDescription }, g.group.description), visibleFields.map((field) => /* @__PURE__ */ React__default.default.createElement(
10007
+ SchemaField,
10008
+ {
10009
+ key: formKey(field),
10010
+ field,
10011
+ control,
10012
+ errors,
10013
+ disabled: allDisabled,
10014
+ dsUid,
10015
+ watchedValues,
10016
+ fieldById
10017
+ }
10018
+ )), showHeaders && /* @__PURE__ */ React__default.default.createElement(
10019
+ AuthorizationHeaderField,
10020
+ {
10021
+ headersFieldKey: formKey(httpHeadersField),
10022
+ control,
10023
+ disabled: allDisabled,
10024
+ watchedValues
10025
+ }
10026
+ ))
10027
+ )
10028
+ );
10029
+ }), submitError && /* @__PURE__ */ React__default.default.createElement(ui.Alert, { severity: "error", title: "Error" }, submitError), /* @__PURE__ */ React__default.default.createElement("div", { className: styles.formButtons }, readOnly ? /* @__PURE__ */ React__default.default.createElement(ui.Button, { variant: "primary", size: "sm", icon: "sync", onClick: onRetest, type: "button" }, "Test") : /* @__PURE__ */ React__default.default.createElement(ui.Button, { variant: "primary", size: "sm", disabled: submitting, type: "submit" }, submitting ? "Saving\u2026" : "Save & Test"), healthError && (renderActions == null ? void 0 : renderActions({ dsUid, dsName, dsType: schema.pluginType, healthError }))))));
10030
+ }
10031
+
10032
+ function useDatasourceConfigForm({ schema, dsUid, onSuccess, onSaving }) {
10033
+ const [submitting, setSubmitting] = React.useState(false);
10034
+ const [submitError, setSubmitError] = React.useState(null);
10035
+ const [initializing, setInitializing] = React.useState(true);
10036
+ const [fetchError, setFetchError] = React.useState(null);
10037
+ const [detectedReadOnly, setDetectedReadOnly] = React.useState(false);
10038
+ const readOnly = detectedReadOnly;
10039
+ const resolvedGroups = React.useMemo(() => {
10040
+ const groups = resolveGroups(schema);
10041
+ const requiredGroup = resolveRequiredFieldsGroup(schema);
10042
+ if (!requiredGroup) {
10043
+ return groups;
10044
+ }
10045
+ return [requiredGroup, ...groups];
10046
+ }, [schema]);
10047
+ const fieldById = React.useMemo(() => {
10048
+ const m = /* @__PURE__ */ new Map();
10049
+ for (const f of schema.fields) {
10050
+ m.set(f.id, f);
10051
+ }
10052
+ return m;
10053
+ }, [schema.fields]);
10054
+ const httpHeadersField = React.useMemo(
10055
+ () => {
10056
+ var _a;
10057
+ return (_a = schema.fields.find((f) => {
10058
+ var _a2;
10059
+ return f.key === "httpHeaders" && ((_a2 = f.storage) == null ? void 0 : _a2.type) === "indexedPair";
10060
+ })) != null ? _a : null;
10061
+ },
10062
+ [schema.fields]
10063
+ );
10064
+ const allStorageFields = React.useMemo(
10065
+ () => schema.fields.filter((f) => f.kind !== "virtual" && !f.isItemField && f.target),
10066
+ [schema.fields]
10067
+ );
10068
+ const {
10069
+ control,
10070
+ handleSubmit,
10071
+ watch,
10072
+ reset,
10073
+ trigger,
10074
+ setValue,
10075
+ formState: { errors }
10076
+ } = reactHookForm.useForm({ mode: "onChange" });
10077
+ const fieldsWithEffects = React.useMemo(() => {
10078
+ const result = [];
10079
+ for (const field of schema.fields) {
10080
+ if (!field.effects || field.effects.length === 0) {
10081
+ continue;
10082
+ }
10083
+ const mapped = field.effects.map((eff) => ({
10084
+ when: eff.when,
10085
+ targets: Object.entries(eff.set).map(([targetId, val]) => {
10086
+ const targetField = fieldById.get(targetId);
10087
+ return { key: targetField ? formKey(targetField) : targetId, value: val };
10088
+ })
10089
+ }));
10090
+ result.push({ sourceKey: formKey(field), effects: mapped });
10091
+ }
10092
+ return result;
10093
+ }, [schema.fields, fieldById]);
10094
+ React.useEffect(() => {
10095
+ let cancelled = false;
10096
+ fetchExistingValues(dsUid, allStorageFields).then((result) => {
10097
+ if (cancelled) {
10098
+ return;
10099
+ }
10100
+ if (result.error) {
10101
+ setFetchError(result.error);
10102
+ setInitializing(false);
10103
+ return;
10104
+ }
10105
+ if (result.readOnly) {
10106
+ setDetectedReadOnly(true);
10107
+ }
10108
+ const defaults = {};
10109
+ for (const field of allStorageFields) {
10110
+ if (field.defaultValue !== void 0) {
10111
+ defaults[formKey(field)] = field.defaultValue;
10112
+ }
10113
+ }
10114
+ const merged = { ...defaults, ...result.values };
10115
+ const virtualValues = computeVirtualFieldValues(schema, merged);
10116
+ reset({ ...merged, ...virtualValues });
10117
+ setInitializing(false);
10118
+ });
10119
+ return () => {
10120
+ cancelled = true;
10121
+ };
10122
+ }, [dsUid, allStorageFields, schema, reset]);
10123
+ const watchedValues = watch();
10124
+ const prevEffectValuesRef = React.useRef({});
10125
+ React.useEffect(() => {
10126
+ if (initializing) {
10127
+ return;
10128
+ }
10129
+ for (const { sourceKey, effects } of fieldsWithEffects) {
10130
+ const currentVal = watchedValues[sourceKey];
10131
+ const prevVal = prevEffectValuesRef.current[sourceKey];
10132
+ if (currentVal === prevVal) {
10133
+ continue;
10134
+ }
10135
+ prevEffectValuesRef.current[sourceKey] = currentVal;
10136
+ for (const eff of effects) {
10137
+ if (evaluateEffectCondition(eff.when, currentVal)) {
10138
+ for (const { key, value } of eff.targets) {
10139
+ setValue(key, value);
10140
+ }
10141
+ break;
10142
+ }
10143
+ }
10144
+ }
10145
+ }, [watchedValues, fieldsWithEffects, initializing, setValue]);
10146
+ const fieldsWithOverrideDefaults = React.useMemo(() => {
10147
+ const result = [];
10148
+ for (const field of schema.fields) {
10149
+ if (!field.overrides || field.overrides.length === 0) {
10150
+ continue;
10151
+ }
10152
+ const ovs = field.overrides.filter((ov) => ov.defaultValue !== void 0).map((ov) => {
10153
+ const parsed = parseDependsOn(ov.when);
10154
+ if (!parsed) {
10155
+ return null;
10156
+ }
10157
+ const depField = fieldById.get(parsed.field);
10158
+ return {
10159
+ depKey: depField ? formKey(depField) : parsed.field,
10160
+ depValue: parsed.value,
10161
+ defaultValue: ov.defaultValue
10162
+ };
10163
+ }).filter(Boolean);
10164
+ if (ovs.length > 0) {
10165
+ result.push({ targetKey: formKey(field), fieldDefault: field.defaultValue, overrides: ovs });
10166
+ }
10167
+ }
10168
+ return result;
10169
+ }, [schema.fields, fieldById]);
10170
+ const prevOverrideDepRef = React.useRef({});
10171
+ React.useEffect(() => {
10172
+ var _a;
10173
+ if (initializing) {
10174
+ return;
10175
+ }
10176
+ for (const { targetKey, fieldDefault, overrides } of fieldsWithOverrideDefaults) {
10177
+ for (const ov of overrides) {
10178
+ const currentDepVal = String((_a = watchedValues[ov.depKey]) != null ? _a : "");
10179
+ const trackKey = `${targetKey}::${ov.depKey}`;
10180
+ const prevDepVal = prevOverrideDepRef.current[trackKey];
10181
+ if (currentDepVal === prevDepVal) {
10182
+ continue;
10183
+ }
10184
+ prevOverrideDepRef.current[trackKey] = currentDepVal;
10185
+ if (currentDepVal === ov.depValue) {
10186
+ setValue(targetKey, ov.defaultValue);
10187
+ } else if (prevDepVal === ov.depValue && fieldDefault !== void 0) {
10188
+ setValue(targetKey, fieldDefault);
10189
+ }
10190
+ }
10191
+ }
10192
+ }, [watchedValues, fieldsWithOverrideDefaults, initializing, setValue]);
10193
+ const isFieldVisible = React.useCallback(
10194
+ (field) => {
10195
+ var _a, _b;
10196
+ if (field.kind === "virtual" && !field.ui) {
10197
+ return false;
10198
+ }
10199
+ if ((_a = field.tags) == null ? void 0 : _a.some((t) => t.startsWith("managed-by:"))) {
10200
+ return false;
10201
+ }
10202
+ if (!field.dependsOn) {
10203
+ return true;
10204
+ }
10205
+ const parsed = parseDependsOn(field.dependsOn);
10206
+ if (!parsed) {
10207
+ return true;
10208
+ }
10209
+ const depField = fieldById.get(parsed.field);
10210
+ const depKey = depField ? formKey(depField) : parsed.field;
10211
+ return String((_b = watchedValues[depKey]) != null ? _b : "") === parsed.value;
10212
+ },
10213
+ [watchedValues, fieldById]
10214
+ );
10215
+ const onSubmit = React.useCallback(
10216
+ async (data) => {
10217
+ setSubmitting(true);
10218
+ setSubmitError(null);
10219
+ onSaving == null ? void 0 : onSaving(true);
10220
+ const minDelay = new Promise((r) => setTimeout(r, 2e3));
10221
+ try {
10222
+ await submitDatasourceConfig(dsUid, data, allStorageFields, isFieldVisible);
10223
+ const [refreshed] = await Promise.all([fetchExistingValues(dsUid, allStorageFields), minDelay]);
10224
+ const defaults = {};
10225
+ for (const field of allStorageFields) {
10226
+ if (field.defaultValue !== void 0) {
10227
+ defaults[formKey(field)] = field.defaultValue;
10228
+ }
10229
+ }
10230
+ const merged = { ...defaults, ...refreshed.values };
10231
+ const virtualValues = computeVirtualFieldValues(schema, merged);
10232
+ reset({ ...merged, ...virtualValues });
10233
+ onSuccess("UPDATED", "Configuration saved.");
10234
+ } catch (err) {
10235
+ await minDelay;
10236
+ setSubmitError(err instanceof Error ? err.message : "Failed to update datasource");
10237
+ } finally {
10238
+ setSubmitting(false);
10239
+ onSaving == null ? void 0 : onSaving(false);
10240
+ }
10241
+ },
10242
+ [dsUid, allStorageFields, isFieldVisible, schema, reset, onSuccess, onSaving]
10243
+ );
10244
+ const isGroupValid = React.useCallback(
10245
+ (group) => {
10246
+ for (const field of group.fields) {
10247
+ if (!isFieldVisible(field)) {
10248
+ continue;
10249
+ }
10250
+ if (errors[formKey(field)]) {
10251
+ return false;
10252
+ }
10253
+ if (isFieldRequired(field, watchedValues, fieldById)) {
10254
+ const val = watchedValues[formKey(field)];
10255
+ if (val === SECURE_FIELD_CONFIGURED) {
10256
+ continue;
10257
+ }
10258
+ if (val === void 0 || val === null || val === "") {
10259
+ return false;
10260
+ }
10261
+ }
10262
+ }
10263
+ return true;
10264
+ },
10265
+ [errors, watchedValues, fieldById, isFieldVisible]
10266
+ );
10267
+ const groupHasData = React.useCallback(
10268
+ (group) => {
10269
+ for (const field of group.fields) {
10270
+ const val = watchedValues[formKey(field)];
10271
+ if (val === void 0 || val === null || val === "" || val === false) {
10272
+ continue;
10273
+ }
10274
+ if (val === field.defaultValue) {
10275
+ continue;
10276
+ }
10277
+ return true;
10278
+ }
10279
+ return false;
10280
+ },
10281
+ [watchedValues]
10282
+ );
10283
+ return {
10284
+ // Schema
10285
+ resolvedGroups,
10286
+ fieldById,
10287
+ httpHeadersField,
10288
+ // Form
10289
+ control,
10290
+ handleSubmit,
10291
+ trigger,
10292
+ errors,
10293
+ watchedValues,
10294
+ // State
10295
+ initializing,
10296
+ fetchError,
10297
+ submitting,
10298
+ submitError,
10299
+ readOnly,
10300
+ // Callbacks
10301
+ isFieldVisible,
10302
+ isGroupValid,
10303
+ groupHasData,
10304
+ onSubmit
10305
+ };
10306
+ }
10307
+
10308
+ function DatasourceConfigWizard(props) {
10309
+ const { schema, dsUid, dsName, onSuccess, onSaving, onRetest, healthError, renderActions, mode = "tab" } = props;
10310
+ const form = useDatasourceConfigForm({ schema, dsUid, onSuccess, onSaving });
10311
+ if (mode === "tab") {
10312
+ return /* @__PURE__ */ React__default.default.createElement(
10313
+ TabLayout,
10314
+ {
10315
+ form,
10316
+ schema,
10317
+ dsUid,
10318
+ dsName,
10319
+ onRetest,
10320
+ healthError,
10321
+ renderActions
10322
+ }
10323
+ );
10324
+ }
10325
+ return /* @__PURE__ */ React__default.default.createElement(
10326
+ WizardLayout,
10327
+ {
10328
+ form,
10329
+ schema,
10330
+ dsUid,
10331
+ dsName,
10332
+ onRetest,
10333
+ healthError,
10334
+ renderActions
10335
+ }
10336
+ );
10337
+ }
10338
+ function WizardLayout({ form, schema, dsUid, dsName, onRetest, healthError, renderActions }) {
10339
+ var _a, _b, _c;
10340
+ const styles = ui.useStyles2(getWizardStyles);
10341
+ const [currentStep, setCurrentStep] = React.useState(0);
10342
+ const {
10343
+ resolvedGroups,
10344
+ fieldById,
10345
+ httpHeadersField,
10346
+ control,
10347
+ handleSubmit,
10348
+ trigger,
10349
+ errors,
10350
+ watchedValues,
10351
+ initializing,
10352
+ fetchError,
10353
+ submitting,
10354
+ submitError,
10355
+ readOnly,
10356
+ isFieldVisible,
10357
+ onSubmit
10358
+ } = form;
10359
+ const arrowSteps = React.useMemo(() => {
10360
+ const requiredGroup = resolvedGroups.find((g) => g.group.id === "_required");
10361
+ if (!requiredGroup) {
10362
+ return new Set(resolvedGroups.map((_, i) => i));
10363
+ }
10364
+ const requiredFieldIds = new Set(requiredGroup.fields.map((f) => f.id));
10365
+ const steps = /* @__PURE__ */ new Set();
10366
+ for (let i = 0; i < resolvedGroups.length; i++) {
10367
+ const g = resolvedGroups[i];
10368
+ if (g.group.id === "_required" || g.fields.some((f) => !requiredFieldIds.has(f.id))) {
10369
+ steps.add(i);
10370
+ }
10371
+ }
10372
+ return steps;
10373
+ }, [resolvedGroups]);
10374
+ const currentResolved = resolvedGroups[currentStep];
10375
+ const isFirstStep = React.useMemo(() => {
10376
+ for (let i = 0; i < currentStep; i++) {
10377
+ if (arrowSteps.has(i)) {
10378
+ return false;
10379
+ }
10380
+ }
10381
+ return true;
10382
+ }, [currentStep, arrowSteps]);
10383
+ const isLastStep = React.useMemo(() => {
10384
+ for (let i = currentStep + 1; i < resolvedGroups.length; i++) {
10385
+ if (arrowSteps.has(i)) {
10386
+ return false;
10387
+ }
10388
+ }
10389
+ return true;
10390
+ }, [currentStep, arrowSteps, resolvedGroups.length]);
10391
+ const visibleFieldsForStep = React.useMemo(
10392
+ () => currentResolved ? currentResolved.fields.filter(isFieldVisible) : [],
10393
+ [currentResolved, isFieldVisible]
10394
+ );
10395
+ const currentGroupValid = React.useMemo(() => {
10396
+ if (!currentResolved) {
10397
+ return true;
10398
+ }
10399
+ for (const field of visibleFieldsForStep) {
10400
+ if (errors[formKey(field)]) {
10401
+ return false;
10402
+ }
10403
+ if (isFieldRequired(field, watchedValues, fieldById)) {
10404
+ const val = watchedValues[formKey(field)];
10405
+ if (val === SECURE_FIELD_CONFIGURED) {
10406
+ continue;
10407
+ }
10408
+ if (val === void 0 || val === null || val === "") {
10409
+ return false;
10410
+ }
10411
+ }
10412
+ }
10413
+ return true;
10414
+ }, [currentResolved, errors, visibleFieldsForStep, watchedValues, fieldById]);
10415
+ const goNext = React.useCallback(async () => {
10416
+ if (!currentResolved) {
10417
+ return;
10418
+ }
10419
+ if (!readOnly) {
10420
+ const visibleKeys = visibleFieldsForStep.map((f) => formKey(f));
10421
+ const valid = await trigger(visibleKeys);
10422
+ if (!valid) {
10423
+ return;
10424
+ }
10425
+ }
10426
+ setCurrentStep((s) => {
10427
+ for (let i = s + 1; i < resolvedGroups.length; i++) {
10428
+ if (arrowSteps.has(i)) {
10429
+ return i;
10430
+ }
10431
+ }
10432
+ return s;
10433
+ });
10434
+ }, [currentResolved, visibleFieldsForStep, trigger, resolvedGroups.length, arrowSteps, readOnly]);
10435
+ const goPrev = React.useCallback(() => {
10436
+ setCurrentStep((s) => {
10437
+ for (let i = s - 1; i >= 0; i--) {
10438
+ if (arrowSteps.has(i)) {
10439
+ return i;
10440
+ }
10441
+ }
10442
+ return s;
10443
+ });
10444
+ }, [arrowSteps]);
10445
+ if (initializing) {
10446
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.container }, /* @__PURE__ */ React__default.default.createElement(ui.Spinner, { size: "sm", inline: true }), " Loading configuration...");
10447
+ }
10448
+ if (fetchError) {
10449
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.container }, /* @__PURE__ */ React__default.default.createElement(ui.Alert, { severity: "error", title: "Failed to load configuration" }, fetchError), /* @__PURE__ */ React__default.default.createElement("div", { className: styles.buttons }, /* @__PURE__ */ React__default.default.createElement(
10450
+ ui.LinkButton,
10451
+ {
10452
+ variant: "secondary",
10453
+ size: "sm",
10454
+ icon: "external-link-alt",
10455
+ href: `/connections/datasources/edit/${dsUid}`
10456
+ },
10457
+ "Open datasource settings"
10458
+ )));
10459
+ }
10460
+ const allDisabled = submitting || readOnly;
10461
+ if (resolvedGroups.length === 0) {
10462
+ return null;
10463
+ }
10464
+ const currentGroup = currentResolved == null ? void 0 : currentResolved.group;
10465
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.container }, submitting && /* @__PURE__ */ React__default.default.createElement("div", { className: styles.overlay }, /* @__PURE__ */ React__default.default.createElement(ui.Spinner, { size: "sm" }), /* @__PURE__ */ React__default.default.createElement("span", null, "Saving & testing\u2026")), readOnly && /* @__PURE__ */ React__default.default.createElement("div", { className: styles.readOnlyBanner }, /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "lock", size: "xs" }), /* @__PURE__ */ React__default.default.createElement("span", null, "Read-only \u2014 managed externally")), /* @__PURE__ */ React__default.default.createElement("div", { className: styles.navBar }, currentGroup && /* @__PURE__ */ React__default.default.createElement(ui.Tooltip, { content: (_a = currentGroup.description) != null ? _a : currentGroup.title }, /* @__PURE__ */ React__default.default.createElement("span", { className: styles.navTitle }, currentGroup.title, /* @__PURE__ */ React__default.default.createElement("span", { className: styles.stepCount }, currentStep + 1, "/", resolvedGroups.length))), /* @__PURE__ */ React__default.default.createElement("div", { className: styles.navActions }, /* @__PURE__ */ React__default.default.createElement(ui.Tooltip, { content: isFirstStep ? "First step" : `Previous: ${(_b = resolvedGroups[currentStep - 1]) == null ? void 0 : _b.group.title}` }, /* @__PURE__ */ React__default.default.createElement(
10466
+ ui.Button,
10467
+ {
10468
+ variant: "secondary",
10469
+ fill: "text",
10470
+ size: "sm",
10471
+ icon: "angle-left",
10472
+ "aria-label": "Previous",
10473
+ onClick: goPrev,
10474
+ disabled: isFirstStep || submitting,
10475
+ type: "button"
10476
+ }
10477
+ )), /* @__PURE__ */ React__default.default.createElement(
10478
+ ui.Select,
10479
+ {
10480
+ options: resolvedGroups.map((g, i) => ({ label: g.group.title, value: i })),
10481
+ value: currentStep,
10482
+ onChange: (v) => {
10483
+ if (v) {
10484
+ setCurrentStep(v.value);
10485
+ }
10486
+ },
10487
+ disabled: submitting,
10488
+ width: 18
10489
+ }
10490
+ ), /* @__PURE__ */ React__default.default.createElement(ui.Tooltip, { content: isLastStep ? "Last step" : `Next: ${(_c = resolvedGroups[currentStep + 1]) == null ? void 0 : _c.group.title}` }, /* @__PURE__ */ React__default.default.createElement(
10491
+ ui.Button,
10492
+ {
10493
+ variant: isLastStep || !readOnly && !currentGroupValid ? "secondary" : "primary",
10494
+ size: "sm",
10495
+ icon: "angle-right",
10496
+ "aria-label": "Next",
10497
+ onClick: goNext,
10498
+ disabled: isLastStep || submitting,
10499
+ type: "button"
10500
+ }
10501
+ )))), currentResolved && /* @__PURE__ */ React__default.default.createElement("form", { onSubmit: handleSubmit(onSubmit), className: styles.form }, visibleFieldsForStep.map((field) => /* @__PURE__ */ React__default.default.createElement(
10502
+ SchemaField,
10503
+ {
10504
+ key: formKey(field),
10505
+ field,
10506
+ control,
10507
+ errors,
10508
+ disabled: allDisabled,
10509
+ dsUid,
10510
+ watchedValues,
10511
+ fieldById
10512
+ }
10513
+ )), (currentResolved.group.id === "_required" || currentResolved.group.id === "auth") && httpHeadersField && /* @__PURE__ */ React__default.default.createElement(
10514
+ AuthorizationHeaderField,
10515
+ {
10516
+ headersFieldKey: formKey(httpHeadersField),
10517
+ control,
10518
+ disabled: allDisabled,
10519
+ watchedValues
10520
+ }
10521
+ ), submitError && /* @__PURE__ */ React__default.default.createElement(ui.Alert, { severity: "error", title: "Error" }, submitError), /* @__PURE__ */ React__default.default.createElement("div", { className: styles.buttons }, readOnly ? /* @__PURE__ */ React__default.default.createElement(ui.Button, { variant: "primary", size: "sm", icon: "sync", onClick: onRetest, type: "button" }, "Test") : /* @__PURE__ */ React__default.default.createElement(ui.Button, { variant: "primary", size: "sm", disabled: submitting || !currentGroupValid, type: "submit" }, submitting ? "Saving..." : "Save & Test"), healthError && (renderActions == null ? void 0 : renderActions({ dsUid, dsName, dsType: schema.pluginType, healthError })))));
10522
+ }
10523
+
10524
+ var __defProp$1 = Object.defineProperty;
10525
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
10526
+ var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
10527
+ const getCustomHeaderRowStyles = ui.stylesFactory(() => {
10528
+ return {
10529
+ layout: css.css`
10530
+ display: flex;
10531
+ align-items: center;
10532
+ margin-bottom: 4px;
10533
+ > * {
10534
+ margin-left: 4px;
10535
+ margin-bottom: 0;
10536
+ height: 100%;
10537
+ &:first-child,
10538
+ &:last-child {
10539
+ margin-left: 0;
10540
+ }
10541
+ }
10542
+ `
10543
+ };
10544
+ });
10545
+ const CustomHeaderRow = ({ header, onBlur, onChange, onRemove, onReset }) => {
10546
+ const styles = getCustomHeaderRowStyles();
10547
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: styles.layout }, /* @__PURE__ */ React__default.default.createElement(
10548
+ ui.LegacyForms.FormField,
10549
+ {
10550
+ label: "Header",
10551
+ name: "name",
10552
+ placeholder: "X-Custom-Header",
10553
+ labelWidth: 5,
10554
+ value: header.name || "",
10555
+ onChange: (e) => onChange({ ...header, name: e.target.value }),
10556
+ onBlur
10557
+ }
10558
+ ), /* @__PURE__ */ React__default.default.createElement(
10559
+ ui.LegacyForms.SecretFormField,
10560
+ {
10561
+ label: "Value",
10562
+ "aria-label": "Value",
10563
+ name: "value",
10564
+ isConfigured: header.configured,
10565
+ value: header.value,
10566
+ labelWidth: 5,
10567
+ inputWidth: header.configured ? 11 : 12,
10568
+ placeholder: "Header Value",
10569
+ onReset: () => onReset(header.id),
10570
+ onChange: (e) => onChange({ ...header, value: e.target.value }),
10571
+ onBlur
10572
+ }
10573
+ ), /* @__PURE__ */ React__default.default.createElement(
10574
+ ui.Button,
10575
+ {
10576
+ type: "button",
10577
+ "aria-label": "Remove header",
10578
+ variant: "secondary",
10579
+ size: "xs",
10580
+ onClick: (_e) => onRemove(header.id)
10581
+ },
10582
+ /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "trash-alt" })
10583
+ ));
10584
+ };
10585
+ CustomHeaderRow.displayName = "CustomHeaderRow";
10586
+ class CustomHeadersSettings extends React.PureComponent {
10587
+ constructor(props) {
10588
+ super(props);
10589
+ __publicField$1(this, "state", {
10590
+ headers: []
10591
+ });
10592
+ __publicField$1(this, "updateSettings", () => {
10593
+ const { headers } = this.state;
10594
+ const newJsonData = Object.fromEntries(
10595
+ Object.entries(this.props.dataSourceConfig.jsonData).filter(([key, val]) => !key.startsWith("httpHeaderName"))
10596
+ );
10597
+ const newSecureJsonData = Object.fromEntries(
10598
+ Object.entries(this.props.dataSourceConfig.secureJsonData || {}).filter(
10599
+ ([key, val]) => !key.startsWith("httpHeaderValue")
10600
+ )
10601
+ );
10602
+ for (const [index, header] of headers.entries()) {
10603
+ newJsonData[`httpHeaderName${index + 1}`] = header.name;
10604
+ if (!header.configured) {
10605
+ newSecureJsonData[`httpHeaderValue${index + 1}`] = header.value;
10606
+ }
10607
+ }
10608
+ this.props.onChange({
10609
+ ...this.props.dataSourceConfig,
10610
+ jsonData: newJsonData,
10611
+ secureJsonData: newSecureJsonData
10612
+ });
10613
+ });
10614
+ __publicField$1(this, "onHeaderAdd", () => {
10615
+ this.setState((prevState) => {
10616
+ return {
10617
+ headers: [...prevState.headers, { id: lodash.uniqueId(), name: "", value: "", configured: false }]
10618
+ };
10619
+ });
10620
+ });
10621
+ __publicField$1(this, "onHeaderChange", (headerIndex, value) => {
10622
+ this.setState(({ headers }) => {
10623
+ return {
10624
+ headers: headers.map((item, index) => {
10625
+ if (headerIndex !== index) {
10626
+ return item;
10627
+ }
10628
+ return { ...value };
10629
+ })
10630
+ };
10631
+ });
10632
+ });
10633
+ __publicField$1(this, "onHeaderReset", (headerId) => {
10634
+ this.setState(({ headers }) => {
10635
+ return {
10636
+ headers: headers.map((h, i) => {
10637
+ if (h.id !== headerId) {
10638
+ return h;
10639
+ }
10640
+ return {
10641
+ ...h,
10642
+ value: "",
10643
+ configured: false
10644
+ };
10645
+ })
10646
+ };
10647
+ });
10648
+ });
10649
+ __publicField$1(this, "onHeaderRemove", (headerId) => {
10650
+ this.setState(
10651
+ ({ headers }) => ({
10652
+ headers: headers.filter((h) => h.id !== headerId)
10653
+ }),
10654
+ this.updateSettings
10655
+ );
10656
+ });
10657
+ const { jsonData, secureJsonData, secureJsonFields } = this.props.dataSourceConfig;
10658
+ this.state = {
10659
+ headers: Object.keys(jsonData).sort().filter((key) => key.startsWith("httpHeaderName")).map((key, index) => {
10660
+ return {
10661
+ id: lodash.uniqueId(),
10662
+ name: jsonData[key],
10663
+ value: secureJsonData !== void 0 ? secureJsonData[key] : "",
10664
+ configured: secureJsonFields && secureJsonFields[`httpHeaderValue${index + 1}`] || false
10665
+ };
10666
+ })
10667
+ };
10668
+ }
10669
+ render() {
10670
+ const { headers } = this.state;
10671
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: "gf-form-group" }, /* @__PURE__ */ React__default.default.createElement("div", { className: "gf-form" }, /* @__PURE__ */ React__default.default.createElement("h6", null, "Custom HTTP Headers")), /* @__PURE__ */ React__default.default.createElement("div", null, headers.map((header, i) => /* @__PURE__ */ React__default.default.createElement(
10672
+ CustomHeaderRow,
10673
+ {
10674
+ key: header.id,
10675
+ header,
10676
+ onChange: (h) => {
10677
+ this.onHeaderChange(i, h);
10678
+ },
10679
+ onBlur: this.updateSettings,
10680
+ onRemove: this.onHeaderRemove,
10681
+ onReset: this.onHeaderReset
10682
+ }
10683
+ ))), /* @__PURE__ */ React__default.default.createElement("div", { className: "gf-form" }, /* @__PURE__ */ React__default.default.createElement(
10684
+ ui.Button,
10685
+ {
10686
+ variant: "secondary",
10687
+ icon: "plus",
10688
+ type: "button",
10689
+ onClick: (e) => {
10690
+ this.onHeaderAdd();
10691
+ }
10692
+ },
10693
+ "Add header"
10694
+ )));
10695
+ }
10696
+ }
10697
+
10698
+ var QueryEditorMode = /* @__PURE__ */ ((QueryEditorMode2) => {
10699
+ QueryEditorMode2["Code"] = "code";
10700
+ QueryEditorMode2["Builder"] = "builder";
10701
+ return QueryEditorMode2;
10702
+ })(QueryEditorMode || {});
10703
+ const BINARY_OPERATIONS_KEY = "Binary operations";
10704
+
10705
+ var __defProp = Object.defineProperty;
10706
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
10707
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
10708
+ class QueryModellerBase {
10709
+ constructor(operationDefinitions, innerQueryPlaceholder) {
10710
+ __publicField(this, "operationsRegistry");
10711
+ __publicField(this, "categories", []);
10712
+ __publicField(this, "innerQueryPlaceholder");
10713
+ this.operationsRegistry = new data.Registry(() => operationDefinitions);
10714
+ this.innerQueryPlaceholder = innerQueryPlaceholder || "<query>";
10715
+ }
10716
+ setOperationCategories(categories) {
10717
+ this.categories = categories;
10718
+ }
10719
+ getOperationsForCategory(category) {
10720
+ return this.operationsRegistry.list().filter((op) => op.category === category && !op.hideFromList);
10721
+ }
10722
+ getAlternativeOperations(key) {
10723
+ return this.operationsRegistry.list().filter((op) => op.alternativesKey && op.alternativesKey === key);
10724
+ }
10725
+ getCategories() {
10726
+ return this.categories;
10727
+ }
10728
+ getOperationDefinition(id) {
10729
+ return this.operationsRegistry.getIfExists(id);
10730
+ }
10731
+ hasBinaryOp(query) {
10732
+ return query.operations.find((op) => {
10733
+ const def = this.getOperationDefinition(op.id);
10734
+ return (def == null ? void 0 : def.category) === BINARY_OPERATIONS_KEY;
10735
+ }) !== void 0;
10736
+ }
10737
+ }
10738
+
10739
+ const CONFLICTING_LABEL_FILTER_ERROR_MESSAGE = "You have conflicting label filters";
10740
+ function LabelFilterItem({
10741
+ item,
10742
+ items,
10743
+ defaultOp,
10744
+ onChange,
10745
+ onDelete,
10746
+ onGetLabelNames,
8615
10747
  onGetLabelValues,
8616
10748
  invalidLabel,
8617
10749
  invalidValue,
@@ -9842,6 +11974,409 @@ const convertUnits = (queryStats) => {
9842
11974
  return text + suffix;
9843
11975
  };
9844
11976
 
11977
+ function generateLLMHint(schema) {
11978
+ var _a, _b, _c, _d;
11979
+ const hints = [];
11980
+ for (const field of schema.fields) {
11981
+ if (((_a = field.ui) == null ? void 0 : _a.component) !== "select" || field.target !== "jsonData" || field.kind === "virtual") {
11982
+ continue;
11983
+ }
11984
+ const options = (_c = (_b = field.ui) == null ? void 0 : _b.options) != null ? _c : [];
11985
+ const values = options.map((opt) => {
11986
+ const isDefault = field.defaultValue != null && String(opt.value) === String(field.defaultValue);
11987
+ return isDefault ? `"${opt.value}" (default)` : `"${opt.value}"`;
11988
+ }).join(", ");
11989
+ if (values) {
11990
+ hints.push(`- ${(_d = field.label) != null ? _d : field.key}: jsonData.${field.key} \u2014 values: ${values}`);
11991
+ }
11992
+ }
11993
+ return hints.join("\n");
11994
+ }
11995
+ function generateTroubleshootingFields(schema) {
11996
+ var _a, _b, _c;
11997
+ const result = [];
11998
+ for (const field of schema.fields) {
11999
+ if (field.kind === "virtual" || field.isItemField) {
12000
+ continue;
12001
+ }
12002
+ const entry = {
12003
+ label: (_a = field.label) != null ? _a : field.key,
12004
+ key: field.target === "root" ? field.key : `${field.target}.${field.key}`,
12005
+ target: (_b = field.target) != null ? _b : "jsonData",
12006
+ type: field.valueType,
12007
+ required: !!field.required
12008
+ };
12009
+ if (field.description) {
12010
+ entry.description = field.description;
12011
+ }
12012
+ if (field.defaultValue != null) {
12013
+ entry.defaultValue = field.defaultValue;
12014
+ }
12015
+ if (((_c = field.ui) == null ? void 0 : _c.options) && field.ui.options.length > 0) {
12016
+ entry.options = field.ui.options.map((o) => String(o.value));
12017
+ }
12018
+ if (field.section) {
12019
+ entry.section = field.section;
12020
+ }
12021
+ if (field.dependsOn) {
12022
+ entry.dependsOn = field.dependsOn;
12023
+ }
12024
+ result.push(entry);
12025
+ }
12026
+ return result;
12027
+ }
12028
+
12029
+ function yamlIndent(depth) {
12030
+ return " ".repeat(depth);
12031
+ }
12032
+ function yamlString(value) {
12033
+ if (value === null || value === void 0) {
12034
+ return '""';
12035
+ }
12036
+ const s = String(value);
12037
+ if (s === "") {
12038
+ return '""';
12039
+ }
12040
+ return yaml__default.default.dump(s, { lineWidth: -1 }).trimEnd();
12041
+ }
12042
+ function yamlValue(value, depth) {
12043
+ if (value === null || value === void 0) {
12044
+ return '""';
12045
+ }
12046
+ if (typeof value === "boolean") {
12047
+ return value ? "true" : "false";
12048
+ }
12049
+ if (typeof value === "number") {
12050
+ return String(value);
12051
+ }
12052
+ if (typeof value === "string") {
12053
+ return yamlString(value);
12054
+ }
12055
+ if (Array.isArray(value)) {
12056
+ if (value.length === 0) {
12057
+ return "[]";
12058
+ }
12059
+ const lines = value.map((item) => {
12060
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) {
12061
+ const entries = Object.entries(item);
12062
+ if (entries.length === 0) {
12063
+ return `${yamlIndent(depth)}- {}`;
12064
+ }
12065
+ const [firstKey, firstVal] = entries[0];
12066
+ const firstLine = `${yamlIndent(depth)}- ${yamlString(firstKey)}: ${yamlValue(firstVal, depth + 2)}`;
12067
+ const rest = entries.slice(1).map(([k, v]) => `${yamlIndent(depth + 1)}${yamlString(k)}: ${yamlValue(v, depth + 2)}`);
12068
+ return [firstLine, ...rest].join("\n");
12069
+ }
12070
+ return `${yamlIndent(depth)}- ${yamlValue(item, depth + 1)}`;
12071
+ });
12072
+ return "\n" + lines.join("\n");
12073
+ }
12074
+ if (typeof value === "object") {
12075
+ const entries = Object.entries(value);
12076
+ if (entries.length === 0) {
12077
+ return "{}";
12078
+ }
12079
+ const lines = entries.map(([k, v]) => `${yamlIndent(depth)}${yamlString(k)}: ${yamlValue(v, depth + 1)}`);
12080
+ return "\n" + lines.join("\n");
12081
+ }
12082
+ return yamlString(value);
12083
+ }
12084
+ function isCertField(field) {
12085
+ var _a;
12086
+ const k = field.key.toLowerCase();
12087
+ return field.target === "secureJsonData" && (k.includes("cert") || k.includes("key") || ((_a = field.ui) == null ? void 0 : _a.component) === "textarea");
12088
+ }
12089
+ function isExcludedFromProvisioning(field) {
12090
+ var _a, _b;
12091
+ if (field.kind === "virtual") {
12092
+ return true;
12093
+ }
12094
+ if (field.isItemField) {
12095
+ return true;
12096
+ }
12097
+ if (((_a = field.tags) == null ? void 0 : _a.some((t) => t.startsWith("managed-by:"))) && field.target !== "root") {
12098
+ return true;
12099
+ }
12100
+ if (((_b = field.storage) == null ? void 0 : _b.type) === "indexedPair") {
12101
+ return true;
12102
+ }
12103
+ return false;
12104
+ }
12105
+ function secretPlaceholder(field) {
12106
+ if (isCertField(field)) {
12107
+ return "|\n xxxxxx";
12108
+ }
12109
+ return "xxxxxx";
12110
+ }
12111
+ function templateValue(field) {
12112
+ var _a;
12113
+ if (field.defaultValue !== void 0) {
12114
+ return field.defaultValue;
12115
+ }
12116
+ if (((_a = field.ui) == null ? void 0 : _a.options) && field.ui.options.length > 0) {
12117
+ return field.ui.options[0].value;
12118
+ }
12119
+ switch (field.valueType) {
12120
+ case "string":
12121
+ return "";
12122
+ case "number":
12123
+ return 0;
12124
+ case "boolean":
12125
+ return false;
12126
+ case "array":
12127
+ return [];
12128
+ case "object":
12129
+ case "map":
12130
+ return {};
12131
+ default:
12132
+ return "";
12133
+ }
12134
+ }
12135
+ function fieldComment(field, indent) {
12136
+ var _a, _b, _c;
12137
+ const parts = [];
12138
+ const label = (_a = field.label) != null ? _a : field.key;
12139
+ let line = label;
12140
+ if (field.required) {
12141
+ line += " (REQUIRED)";
12142
+ }
12143
+ if (field.description) {
12144
+ line += ` \u2014 ${field.description}`;
12145
+ }
12146
+ parts.push(`${indent}# ${line}`);
12147
+ const options = (_b = field.ui) == null ? void 0 : _b.options;
12148
+ if (options && options.length > 0) {
12149
+ const vals = options.map((o) => String(o.value)).join(", ");
12150
+ parts.push(`${indent}# Allowed values: ${vals}`);
12151
+ }
12152
+ const allowedValuesRule = (_c = field.validations) == null ? void 0 : _c.find((v) => v.type === "allowedValues");
12153
+ if (allowedValuesRule && !options) {
12154
+ const vals = allowedValuesRule.values.map((v) => String(v)).join(", ");
12155
+ parts.push(`${indent}# Allowed values: ${vals}`);
12156
+ }
12157
+ if (field.dependsOn) {
12158
+ parts.push(`${indent}# Only when: ${field.dependsOn}`);
12159
+ }
12160
+ return parts.join("\n");
12161
+ }
12162
+ function toProvisioningYaml(schema, values, options) {
12163
+ var _a, _b, _c, _d, _e, _f;
12164
+ const isTemplate = !values;
12165
+ const showComments = (_a = options == null ? void 0 : options.comments) != null ? _a : isTemplate;
12166
+ const indent2 = " ";
12167
+ const indent3 = " ";
12168
+ const groups = resolveGroups(schema);
12169
+ const rootFields = [];
12170
+ const jsonDataFieldsByGroup = [];
12171
+ const secureJsonDataFieldsByGroup = [];
12172
+ const virtualFieldsWithOptions = [];
12173
+ for (const { group, fields } of groups) {
12174
+ const jd = [];
12175
+ const sd = [];
12176
+ for (const field of fields) {
12177
+ if (field.kind === "virtual" && ((_b = field.ui) == null ? void 0 : _b.options) && field.ui.options.length > 0) {
12178
+ virtualFieldsWithOptions.push(field);
12179
+ continue;
12180
+ }
12181
+ if (isExcludedFromProvisioning(field)) {
12182
+ continue;
12183
+ }
12184
+ switch (field.target) {
12185
+ case "root":
12186
+ rootFields.push(field);
12187
+ break;
12188
+ case "jsonData":
12189
+ jd.push(field);
12190
+ break;
12191
+ case "secureJsonData":
12192
+ sd.push(field);
12193
+ break;
12194
+ }
12195
+ }
12196
+ if (jd.length > 0) {
12197
+ jsonDataFieldsByGroup.push({ group, fields: jd });
12198
+ }
12199
+ if (sd.length > 0) {
12200
+ secureJsonDataFieldsByGroup.push({ group, fields: sd });
12201
+ }
12202
+ }
12203
+ const allSecureJsonDataFields = secureJsonDataFieldsByGroup.flatMap((g) => g.fields);
12204
+ const groupedFieldIds = new Set(groups.flatMap(({ group }) => group.fieldRefs));
12205
+ for (const field of schema.fields) {
12206
+ if (field.target === "root" && !groupedFieldIds.has(field.id) && !isExcludedFromProvisioning(field)) {
12207
+ rootFields.push(field);
12208
+ }
12209
+ }
12210
+ const lines = [];
12211
+ lines.push("apiVersion: 1");
12212
+ lines.push("");
12213
+ lines.push("datasources:");
12214
+ lines.push(`${indent2.slice(2)}- name: ${yamlString((_d = (_c = options == null ? void 0 : options.name) != null ? _c : values == null ? void 0 : values.name) != null ? _d : `my-${schema.pluginType}`)}`);
12215
+ lines.push(`${indent2}type: ${schema.pluginType}`);
12216
+ if (!isTemplate && (values == null ? void 0 : values.uid)) {
12217
+ lines.push(`${indent2}uid: ${yamlString(values.uid)}`);
12218
+ }
12219
+ const ALREADY_EMITTED_ROOT = /* @__PURE__ */ new Set(["name", "type", "uid"]);
12220
+ for (const field of rootFields) {
12221
+ if (ALREADY_EMITTED_ROOT.has(field.key)) {
12222
+ continue;
12223
+ }
12224
+ const val = values ? values[field.key] : templateValue(field);
12225
+ if (val === void 0 || val === null) {
12226
+ continue;
12227
+ }
12228
+ if (!isTemplate && val === false) {
12229
+ continue;
12230
+ }
12231
+ if (showComments) {
12232
+ lines.push(fieldComment(field, indent2));
12233
+ }
12234
+ lines.push(`${indent2}${field.key}: ${yamlValue(val, 3)}`);
12235
+ }
12236
+ if (showComments) {
12237
+ for (const vf of virtualFieldsWithOptions) {
12238
+ const label = (_e = vf.label) != null ? _e : vf.key;
12239
+ const opts = vf.ui.options.map((o) => `${String(o.value)} (${o.label})`).join(", ");
12240
+ lines.push(`${indent2}# ${label}: ${opts}`);
12241
+ if (vf.description) {
12242
+ lines.push(`${indent2}# ${vf.description}`);
12243
+ }
12244
+ }
12245
+ }
12246
+ const emittedJsonDataKeys = /* @__PURE__ */ new Set();
12247
+ const emittedSecureJsonDataKeys = /* @__PURE__ */ new Set();
12248
+ const jsonDataValues = values == null ? void 0 : values.jsonData;
12249
+ const hasJsonDataFromSchema = jsonDataFieldsByGroup.length > 0;
12250
+ const hasJsonDataFromValues = !isTemplate && jsonDataValues && Object.keys(jsonDataValues).length > 0;
12251
+ if (hasJsonDataFromSchema || hasJsonDataFromValues) {
12252
+ lines.push(`${indent2}jsonData:`);
12253
+ for (const { group, fields: groupFields } of jsonDataFieldsByGroup) {
12254
+ if (showComments && jsonDataFieldsByGroup.length > 1) {
12255
+ lines.push(`${indent3}# --- ${group.title} ---`);
12256
+ }
12257
+ for (const field of groupFields) {
12258
+ const val = values ? getNestedValue(values, "jsonData", field) : templateValue(field);
12259
+ if (val === void 0 || val === null) {
12260
+ continue;
12261
+ }
12262
+ if (!isTemplate && field.defaultValue !== void 0 && val === field.defaultValue) {
12263
+ continue;
12264
+ }
12265
+ emittedJsonDataKeys.add(field.key);
12266
+ if (showComments) {
12267
+ lines.push(fieldComment(field, indent3));
12268
+ }
12269
+ const rendered = yamlValue(val, 4);
12270
+ if (rendered.startsWith("\n")) {
12271
+ lines.push(`${indent3}${field.key}:${rendered}`);
12272
+ } else {
12273
+ lines.push(`${indent3}${field.key}: ${rendered}`);
12274
+ }
12275
+ }
12276
+ }
12277
+ if (!isTemplate && jsonDataValues) {
12278
+ for (const [key, val] of Object.entries(jsonDataValues)) {
12279
+ if (emittedJsonDataKeys.has(key)) {
12280
+ continue;
12281
+ }
12282
+ if (val === void 0 || val === null) {
12283
+ continue;
12284
+ }
12285
+ const rendered = yamlValue(val, 4);
12286
+ if (rendered.startsWith("\n")) {
12287
+ lines.push(`${indent3}${key}:${rendered}`);
12288
+ } else {
12289
+ lines.push(`${indent3}${key}: ${rendered}`);
12290
+ }
12291
+ }
12292
+ }
12293
+ }
12294
+ const secureJsonFields = (_f = values == null ? void 0 : values.secureJsonFields) != null ? _f : {};
12295
+ const inferredSecureKeys = !isTemplate ? inferSecureJsonDataKeys(jsonDataValues) : [];
12296
+ const activeSecureFields = isTemplate ? allSecureJsonDataFields : allSecureJsonDataFields.filter((f) => secureJsonFields[f.key] === true);
12297
+ if (activeSecureFields.length > 0 || inferredSecureKeys.length > 0) {
12298
+ lines.push(`${indent2}secureJsonData:`);
12299
+ for (const field of activeSecureFields) {
12300
+ emittedSecureJsonDataKeys.add(field.key);
12301
+ if (showComments) {
12302
+ lines.push(fieldComment(field, indent3));
12303
+ }
12304
+ lines.push(`${indent3}${field.key}: ${secretPlaceholder(field)}`);
12305
+ }
12306
+ for (const key of inferredSecureKeys) {
12307
+ if (emittedSecureJsonDataKeys.has(key)) {
12308
+ continue;
12309
+ }
12310
+ lines.push(`${indent3}${key}: xxxxxx`);
12311
+ }
12312
+ }
12313
+ return lines.join("\n");
12314
+ }
12315
+ function inferSecureJsonDataKeys(jsonData) {
12316
+ if (!jsonData) {
12317
+ return [];
12318
+ }
12319
+ const keys = [];
12320
+ for (const key of Object.keys(jsonData)) {
12321
+ const match = key.match(/^httpHeaderName(\d+)$/);
12322
+ if (match) {
12323
+ keys.push(`httpHeaderValue${match[1]}`);
12324
+ }
12325
+ }
12326
+ return keys;
12327
+ }
12328
+ function getNestedValue(values, target, field) {
12329
+ const nested = values[target];
12330
+ if (nested && typeof nested === "object") {
12331
+ return nested[field.key];
12332
+ }
12333
+ return void 0;
12334
+ }
12335
+ function datasourceToProvisioningYaml(ds, schema) {
12336
+ if (schema) {
12337
+ return toProvisioningYaml(schema, ds, { comments: false });
12338
+ }
12339
+ const lines = [];
12340
+ lines.push("apiVersion: 1");
12341
+ lines.push("");
12342
+ lines.push("datasources:");
12343
+ lines.push(` - name: ${yamlString(ds.name)}`);
12344
+ if (ds.uid) {
12345
+ lines.push(` uid: ${yamlString(ds.uid)}`);
12346
+ }
12347
+ lines.push(` type: ${yamlString(ds.type)}`);
12348
+ if (ds.url) {
12349
+ lines.push(` url: ${yamlString(ds.url)}`);
12350
+ }
12351
+ if (ds.database) {
12352
+ lines.push(` database: ${yamlString(ds.database)}`);
12353
+ }
12354
+ if (ds.isDefault) {
12355
+ lines.push(" isDefault: true");
12356
+ }
12357
+ if (ds.basicAuth) {
12358
+ lines.push(" basicAuth: true");
12359
+ if (ds.basicAuthUser) {
12360
+ lines.push(` basicAuthUser: ${yamlString(ds.basicAuthUser)}`);
12361
+ }
12362
+ }
12363
+ const jsonData = ds.jsonData;
12364
+ if (jsonData && Object.keys(jsonData).length > 0) {
12365
+ lines.push(" jsonData:");
12366
+ for (const [key, val] of Object.entries(jsonData)) {
12367
+ const rendered = yamlValue(val, 4);
12368
+ if (rendered.startsWith("\n")) {
12369
+ lines.push(` ${key}:${rendered}`);
12370
+ } else {
12371
+ lines.push(` ${key}: ${rendered}`);
12372
+ }
12373
+ }
12374
+ }
12375
+ lines.push(" # secureJsonData: (secrets are not exported \u2014 add manually)");
12376
+ lines.push(" # mySecret: xxxxxx");
12377
+ return lines.join("\n");
12378
+ }
12379
+
9845
12380
  exports.AccessoryButton = AccessoryButton;
9846
12381
  exports.AdvancedHttpSettings = AdvancedHttpSettings;
9847
12382
  exports.Auth = Auth;
@@ -9861,6 +12396,7 @@ exports.DataLinks = DataLinks;
9861
12396
  exports.DataSourceDescription = DataSourceDescription;
9862
12397
  exports.DataSourcePicker = DataSourcePicker;
9863
12398
  exports.DatasetSelector = DatasetSelector;
12399
+ exports.DatasourceConfigWizard = DatasourceConfigWizard;
9864
12400
  exports.DatePicker = DatePicker;
9865
12401
  exports.DatePickerWithInput = DatePickerWithInput;
9866
12402
  exports.DebounceInput = DebounceInput;
@@ -9896,6 +12432,7 @@ exports.QueryModellerBase = QueryModellerBase;
9896
12432
  exports.QueryOptionGroup = QueryOptionGroup;
9897
12433
  exports.RawQuery = RawQuery;
9898
12434
  exports.RunQueryButton = RunQueryButton;
12435
+ exports.SECURE_FIELD_CONFIGURED = SECURE_FIELD_CONFIGURED;
9899
12436
  exports.SQLEditor = SQLEditor;
9900
12437
  exports.SQLEditorMode = SQLEditorMode;
9901
12438
  exports.SQLEditorTestUtils = SQLEditorTestUtils;
@@ -9909,10 +12446,26 @@ exports.SuggestionKind = SuggestionKind;
9909
12446
  exports.TLSSettings = TLSSettings;
9910
12447
  exports.TableSelector = TableSelector;
9911
12448
  exports.TokenType = TokenType;
12449
+ exports.buildDatasourceConfigPayload = buildDatasourceConfigPayload;
12450
+ exports.computeVirtualFieldValues = computeVirtualFieldValues;
9912
12451
  exports.convertLegacyAuthProps = convertLegacyAuthProps;
12452
+ exports.datasourceToProvisioningYaml = datasourceToProvisioningYaml;
12453
+ exports.evaluateComputedRead = evaluateComputedRead;
12454
+ exports.expandIndexedPair = expandIndexedPair;
12455
+ exports.fetchExistingValues = fetchExistingValues;
12456
+ exports.flattenIndexedPair = flattenIndexedPair;
12457
+ exports.formKey = formKey;
9913
12458
  exports.formatDate = formatDate;
12459
+ exports.generateLLMHint = generateLLMHint;
12460
+ exports.generateTroubleshootingFields = generateTroubleshootingFields;
9914
12461
  exports.getStandardSQLCompletionProvider = getStandardSQLCompletionProvider;
9915
12462
  exports.grafanaStandardSQLLanguage = language;
9916
12463
  exports.grafanaStandardSQLLanguageConf = conf;
12464
+ exports.parseDependsOn = parseDependsOn;
12465
+ exports.resolveActiveOverride = resolveActiveOverride;
12466
+ exports.resolveGroups = resolveGroups;
12467
+ exports.resolveRequiredFieldsGroup = resolveRequiredFieldsGroup;
12468
+ exports.submitDatasourceConfig = submitDatasourceConfig;
9917
12469
  exports.toOption = toOption;
12470
+ exports.toProvisioningYaml = toProvisioningYaml;
9918
12471
  //# sourceMappingURL=index.cjs.map