@grafana/plugin-ui 0.11.0 → 0.12.0

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 (30) hide show
  1. package/README.md +20 -0
  2. package/dist/cjs/index.cjs +79 -122
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/cjs/index.d.cts +9 -17
  5. package/dist/esm/components/QueryEditor/CatalogSelector.js +0 -1
  6. package/dist/esm/components/QueryEditor/CatalogSelector.js.map +1 -1
  7. package/dist/esm/components/QueryEditor/DatasetSelector.js +9 -4
  8. package/dist/esm/components/QueryEditor/DatasetSelector.js.map +1 -1
  9. package/dist/esm/components/QueryEditor/QueryEditor.js +5 -2
  10. package/dist/esm/components/QueryEditor/QueryEditor.js.map +1 -1
  11. package/dist/esm/components/QueryEditor/QueryHeader.js +35 -49
  12. package/dist/esm/components/QueryEditor/QueryHeader.js.map +1 -1
  13. package/dist/esm/components/QueryEditor/TableSelector.js +3 -6
  14. package/dist/esm/components/QueryEditor/TableSelector.js.map +1 -1
  15. package/dist/esm/components/QueryEditor/types.js.map +1 -1
  16. package/dist/esm/components/QueryEditor/utils/sql.utils.js +7 -9
  17. package/dist/esm/components/QueryEditor/utils/sql.utils.js.map +1 -1
  18. package/dist/esm/components/QueryEditor/utils/useSqlChange.js +7 -1
  19. package/dist/esm/components/QueryEditor/utils/useSqlChange.js.map +1 -1
  20. package/dist/esm/components/SQLEditor/types.js.map +1 -1
  21. package/dist/esm/components/SQLEditor/utils/tokenUtils.js +2 -0
  22. package/dist/esm/components/SQLEditor/utils/tokenUtils.js.map +1 -1
  23. package/dist/esm/components/VisualQueryBuilder/components/QueryOptionGroup.js +11 -2
  24. package/dist/esm/components/VisualQueryBuilder/components/QueryOptionGroup.js.map +1 -1
  25. package/dist/esm/index.d.ts +9 -17
  26. package/dist/esm/index.js +0 -1
  27. package/dist/esm/index.js.map +1 -1
  28. package/package.json +2 -1
  29. package/dist/esm/components/QueryEditor/SchemaSelector.js +0 -56
  30. package/dist/esm/components/QueryEditor/SchemaSelector.js.map +0 -1
package/README.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  React components for Grafana plugins
4
4
 
5
+ ## Development
6
+ Requires running a local version of Grafana from source.
7
+ ### Setting up local version of @grafana/plugin-ui with app plugin
8
+
9
+ 1. Run `yarn install && yarn dev`
10
+ 1. Run `yarn link ../path/to/plugin-ui` from app plugin directory. Make sure not to commit the changes to grafana/grafana that are introduced to the package.json.
11
+ 1. Start app plugin development server.
12
+
13
+ To avoid needing to manually rebuild core grafana on every change you make in this repo while developing, instead of running `yarn dev`, run
14
+ ```bash
15
+ yarn tsc -p ./tsconfig.build.json && yarn rollup -c rollup.config.ts --configPlugin esbuild -w --watch.onEnd="cd ../grafana/public/app/plugins/datasource/loki && yarn build
16
+ ```
17
+ Replacing the --watch.onEnd command with whatever you are targeting.
18
+
19
+ There is a better way of doing this, when you find it, please add it here so it's not so painful working with this repo.
20
+
21
+ ## Deploying
22
+ Increment the version in the package.json and make sure the [CHANGELOG.md](CHANGELOG.md) includes a message for each merged PR. The `publish-npm` workflow should trigger on version changes, which will publish the release on npm.
23
+
5
24
  ## Grafana compatibility
6
25
 
7
26
  Plugin-ui@0.9.0 is compatible with Grafana versions 10.4.0 and higher. If the `grafanaDependency` field in your plugin.json file is set to an earlier version, you should amend it to `>=10.4.0`
@@ -9,6 +28,7 @@ When you do that, consider also incrementing your plugin's major version to make
9
28
 
10
29
  ## Storybook
11
30
 
31
+ Storybook is pretty broken, components link to assets that only exist within Grafana, as such most components haven't bothered to add support for storybook.
12
32
  ```
13
33
  yarn storybook
14
34
  ```
@@ -699,21 +699,19 @@ var QueryEditorExpressionType = /* @__PURE__ */ ((QueryEditorExpressionType2) =>
699
699
  function getRawSqlFn(db) {
700
700
  return db.toRawSql ? db.toRawSql : (query) => toRawSql(query, Boolean(db.disableDatasets));
701
701
  }
702
- function toRawSql({ sql, dataset, table }, disableDatasets) {
702
+ function toRawSql({ sql, dataset, catalog, table }, disableDatasets) {
703
703
  var _a, _b, _c, _d;
704
704
  let rawQuery = "";
705
705
  if (!sql || !haveColumns(sql.columns)) {
706
706
  return rawQuery;
707
707
  }
708
708
  rawQuery += createSelectClause(sql.columns);
709
- if (disableDatasets) {
710
- if (table) {
711
- rawQuery += `FROM ${table} `;
712
- }
713
- } else {
714
- if (dataset && table) {
715
- rawQuery += `FROM ${dataset}.${table} `;
716
- }
709
+ if (catalog && dataset && table) {
710
+ rawQuery += `FROM ${catalog}.${dataset}.${table} `;
711
+ } else if (!disableDatasets && dataset && table) {
712
+ rawQuery += `FROM ${dataset}.${table} `;
713
+ } else if (table) {
714
+ rawQuery += `FROM ${table} `;
717
715
  }
718
716
  if (sql.whereString) {
719
717
  rawQuery += `WHERE ${sql.whereString} `;
@@ -2240,6 +2238,8 @@ const defaultTableNameParser = (token) => {
2240
2238
  return { table: parts[0] };
2241
2239
  } else if ((parts == null ? undefined : parts.length) === 2) {
2242
2240
  return { schema: parts[0], table: parts[1] };
2241
+ } else if ((parts == null ? undefined : parts.length) === 3) {
2242
+ return { catalog: parts[0], schema: parts[1], table: parts[2] };
2243
2243
  }
2244
2244
  return null;
2245
2245
  };
@@ -5866,21 +5866,24 @@ function ConfirmModal({ isOpen, onCancel, onDiscard, onCopy }) {
5866
5866
  const DatasetSelector = ({
5867
5867
  db,
5868
5868
  dataset,
5869
+ catalog,
5869
5870
  value,
5870
5871
  onChange,
5871
5872
  disabled,
5872
5873
  className,
5873
5874
  applyDefault,
5874
- inputId
5875
+ inputId,
5876
+ enableCatalogs,
5877
+ "data-testid": dataTestId
5875
5878
  }) => {
5876
5879
  const state = reactUse.useAsync(async () => {
5877
5880
  if (dataset) {
5878
5881
  onChange(toOption(dataset));
5879
5882
  return [toOption(dataset)];
5880
5883
  }
5881
- const datasets = await db.datasets();
5884
+ const datasets = await db.datasets(catalog);
5882
5885
  return datasets.map(toOption);
5883
- }, []);
5886
+ }, [catalog]);
5884
5887
  React.useEffect(() => {
5885
5888
  if (!applyDefault) {
5886
5889
  return;
@@ -5908,7 +5911,9 @@ const DatasetSelector = ({
5908
5911
  onChange,
5909
5912
  disabled,
5910
5913
  isLoading: state.loading,
5911
- menuShouldPortal: true
5914
+ menuShouldPortal: true,
5915
+ "data-testid": dataTestId,
5916
+ placeholder: enableCatalogs ? "Select schema" : "Select dataset"
5912
5917
  }
5913
5918
  );
5914
5919
  };
@@ -5953,55 +5958,6 @@ const CatalogSelector = ({ db, inputId, value, onChange }) => {
5953
5958
  placeholder: "Select catalog",
5954
5959
  isClearable: true,
5955
5960
  allowCustomValue: true,
5956
- disabled: isLoading,
5957
- menuShouldPortal: true
5958
- }
5959
- );
5960
- };
5961
-
5962
- const SchemaSelector = ({ db, inputId, catalog, value, onChange }) => {
5963
- const [schemas, setSchemas] = React.useState([]);
5964
- const [isLoading, setIsLoading] = React.useState(false);
5965
- const loadSchemas = React.useCallback(async () => {
5966
- if (!db.schemas || !catalog) {
5967
- setSchemas([]);
5968
- return;
5969
- }
5970
- setIsLoading(true);
5971
- try {
5972
- const schemaList = await db.schemas(catalog);
5973
- const schemaOptions = schemaList.map((schema) => ({
5974
- label: schema,
5975
- value: schema
5976
- }));
5977
- setSchemas(schemaOptions);
5978
- } catch (error) {
5979
- console.error("Error loading schemas:", error);
5980
- setSchemas([]);
5981
- } finally {
5982
- setIsLoading(false);
5983
- }
5984
- }, [db, catalog]);
5985
- React.useEffect(() => {
5986
- loadSchemas();
5987
- }, [db, catalog, loadSchemas]);
5988
- const handleChange = (selectable) => {
5989
- onChange((selectable == null ? undefined : selectable.value) || null);
5990
- };
5991
- const selectedValue = schemas.find((schema) => schema.value === value) || null;
5992
- const isDisabled = isLoading || !catalog;
5993
- return /* @__PURE__ */ jsxRuntime.jsx(
5994
- ui.Select,
5995
- {
5996
- inputId,
5997
- options: schemas,
5998
- value: selectedValue,
5999
- onChange: handleChange,
6000
- isLoading,
6001
- placeholder: "Select schema",
6002
- isClearable: true,
6003
- allowCustomValue: true,
6004
- disabled: isDisabled,
6005
5961
  menuShouldPortal: true
6006
5962
  }
6007
5963
  );
@@ -6011,7 +5967,6 @@ const TableSelector = ({
6011
5967
  db,
6012
5968
  dataset,
6013
5969
  catalog,
6014
- schema,
6015
5970
  value,
6016
5971
  className,
6017
5972
  onChange,
@@ -6022,19 +5977,17 @@ const TableSelector = ({
6022
5977
  if (!dataset && !catalog) {
6023
5978
  return [];
6024
5979
  }
6025
- if (enableCatalogs && (!catalog || !schema)) {
5980
+ if (enableCatalogs && (!catalog || !dataset)) {
6026
5981
  return [];
6027
5982
  }
6028
- const tables = await db.tables(dataset, catalog, schema);
5983
+ const tables = await db.tables(dataset, catalog);
6029
5984
  return tables.map(data.toOption);
6030
- }, [dataset, catalog, schema, enableCatalogs]);
6031
- const isDisabled = state.loading || enableCatalogs && (!catalog || !schema);
5985
+ }, [dataset, catalog, enableCatalogs]);
6032
5986
  return /* @__PURE__ */ jsxRuntime.jsx(
6033
5987
  ui.Select,
6034
5988
  {
6035
5989
  inputId,
6036
5990
  className,
6037
- disabled: isDisabled,
6038
5991
  "aria-label": "Table selector",
6039
5992
  value,
6040
5993
  options: state.value,
@@ -6110,6 +6063,7 @@ function QueryHeader({
6110
6063
  const toRawSql = getRawSqlFn(db);
6111
6064
  const htmlId = React.useId();
6112
6065
  const catalogsEnabled = enableCatalogs != null ? enableCatalogs : db.disableCatalogs === false;
6066
+ const effectiveEnableDatasets = catalogsEnabled ? true : enableDatasets;
6113
6067
  const onEditorModeChange = React.useCallback(
6114
6068
  (newEditorMode) => {
6115
6069
  if (editorMode === EditorMode.Code) {
@@ -6125,12 +6079,13 @@ function QueryHeader({
6125
6079
  onChange(next);
6126
6080
  };
6127
6081
  const onDatasetChange = (e) => {
6128
- if (e.value === query.dataset) {
6082
+ const datasetValue = e.value || undefined;
6083
+ if (datasetValue === query.dataset) {
6129
6084
  return;
6130
6085
  }
6131
6086
  const next = {
6132
6087
  ...query,
6133
- dataset: e.value,
6088
+ dataset: datasetValue,
6134
6089
  table: undefined,
6135
6090
  sql: undefined,
6136
6091
  rawSql: ""
@@ -6138,26 +6093,15 @@ function QueryHeader({
6138
6093
  onChange(next);
6139
6094
  };
6140
6095
  const onCatalogChange = (catalog) => {
6141
- if (catalog === query.catalog) {
6096
+ const catalogValue = catalog || undefined;
6097
+ if (catalogValue === query.catalog) {
6142
6098
  return;
6143
6099
  }
6144
6100
  const next = {
6145
6101
  ...query,
6146
- catalog: catalog || undefined,
6147
- schema: undefined,
6148
- table: undefined,
6149
- sql: undefined,
6150
- rawSql: ""
6151
- };
6152
- onChange(next);
6153
- };
6154
- const onSchemaChange = (schema) => {
6155
- if (schema === query.schema) {
6156
- return;
6157
- }
6158
- const next = {
6159
- ...query,
6160
- schema: schema || undefined,
6102
+ catalog: catalogValue,
6103
+ dataset: undefined,
6104
+ // Reset dataset (which acts as schema when catalog is present)
6161
6105
  table: undefined,
6162
6106
  sql: undefined,
6163
6107
  rawSql: ""
@@ -6266,45 +6210,41 @@ function QueryHeader({
6266
6210
  editorMode === EditorMode.Builder && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6267
6211
  /* @__PURE__ */ jsxRuntime.jsx(Space, { v: 0.5 }),
6268
6212
  /* @__PURE__ */ jsxRuntime.jsxs(EditorRow$1, { children: [
6269
- enableDatasets === true && !catalogsEnabled && /* @__PURE__ */ jsxRuntime.jsx(EditorField$1, { label: labels.get("dataset") || "Dataset", width: 25, children: /* @__PURE__ */ jsxRuntime.jsx(
6270
- DatasetSelector,
6213
+ catalogsEnabled && /* @__PURE__ */ jsxRuntime.jsx(EditorField$1, { label: labels.get("catalog") || "Catalog", width: 25, children: /* @__PURE__ */ jsxRuntime.jsx(
6214
+ CatalogSelector,
6271
6215
  {
6272
6216
  db,
6273
- inputId: `sql-dataset-${htmlId}`,
6274
- dataset: defaultDataset,
6275
- value: query.dataset === undefined ? null : query.dataset,
6276
- onChange: onDatasetChange
6217
+ inputId: `sql-catalog-${htmlId}`,
6218
+ value: query.catalog === undefined ? null : query.catalog,
6219
+ onChange: onCatalogChange
6277
6220
  }
6278
6221
  ) }),
6279
- catalogsEnabled && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6280
- /* @__PURE__ */ jsxRuntime.jsx(EditorField$1, { label: labels.get("catalog") || "Catalog", width: 25, children: /* @__PURE__ */ jsxRuntime.jsx(
6281
- CatalogSelector,
6282
- {
6283
- db,
6284
- inputId: `sql-catalog-${htmlId}`,
6285
- value: query.catalog === undefined ? null : query.catalog,
6286
- onChange: onCatalogChange
6287
- }
6288
- ) }),
6289
- /* @__PURE__ */ jsxRuntime.jsx(EditorField$1, { label: labels.get("schema") || "Schema", width: 25, children: /* @__PURE__ */ jsxRuntime.jsx(
6290
- SchemaSelector,
6291
- {
6292
- db,
6293
- inputId: `sql-schema-${htmlId}`,
6294
- catalog: query.catalog,
6295
- value: query.schema === undefined ? null : query.schema,
6296
- onChange: onSchemaChange
6297
- }
6298
- ) })
6299
- ] }),
6300
- /* @__PURE__ */ jsxRuntime.jsx(EditorField$1, { label: "Table", width: 25, children: /* @__PURE__ */ jsxRuntime.jsx(
6222
+ effectiveEnableDatasets && /* @__PURE__ */ jsxRuntime.jsx(
6223
+ EditorField$1,
6224
+ {
6225
+ label: catalogsEnabled ? labels.get("schema") || "Schema" : labels.get("dataset") || "Dataset",
6226
+ width: 25,
6227
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6228
+ DatasetSelector,
6229
+ {
6230
+ db,
6231
+ inputId: catalogsEnabled ? `sql-schema-${htmlId}` : `sql-dataset-${htmlId}`,
6232
+ "data-testid": catalogsEnabled ? "schema-selector" : "dataset-selector",
6233
+ dataset: catalogsEnabled ? undefined : defaultDataset,
6234
+ value: query.dataset === undefined ? null : query.dataset,
6235
+ onChange: onDatasetChange,
6236
+ catalog: catalogsEnabled ? query.catalog : undefined
6237
+ }
6238
+ )
6239
+ }
6240
+ ),
6241
+ /* @__PURE__ */ jsxRuntime.jsx(EditorField$1, { label: labels.get("table") || "Table", width: 25, children: /* @__PURE__ */ jsxRuntime.jsx(
6301
6242
  TableSelector,
6302
6243
  {
6303
6244
  db,
6304
6245
  inputId: `sql-table-${htmlId}`,
6305
- dataset: catalogsEnabled ? undefined : query.dataset || defaultDataset,
6246
+ dataset: query.dataset || (catalogsEnabled ? undefined : defaultDataset),
6306
6247
  catalog: catalogsEnabled ? query.catalog : undefined,
6307
- schema: catalogsEnabled ? query.schema : undefined,
6308
6248
  query,
6309
6249
  value: query.table === undefined ? null : query.table,
6310
6250
  onChange: onTableChange,
@@ -6612,7 +6552,13 @@ function useSqlChange({ query, onQueryChange, db }) {
6612
6552
  const onSqlChange = React.useCallback(
6613
6553
  (sql) => {
6614
6554
  const toRawSql = getRawSqlFn(db);
6615
- const rawSql = toRawSql({ sql, dataset: query.dataset, table: query.table, refId: query.refId });
6555
+ const rawSql = toRawSql({
6556
+ sql,
6557
+ catalog: query.catalog,
6558
+ dataset: query.dataset,
6559
+ table: query.table,
6560
+ refId: query.refId
6561
+ });
6616
6562
  const newQuery = { ...query, sql, rawSql };
6617
6563
  onQueryChange(newQuery);
6618
6564
  },
@@ -7480,14 +7426,17 @@ function SqlQueryEditor({ datasource, query, onChange, onRunQuery, range }) {
7480
7426
  if (loading || error) {
7481
7427
  return null;
7482
7428
  }
7429
+ const catalogsEnabled = db.disableCatalogs === false;
7430
+ const datasetsEnabled = !db.disableDatasets;
7431
+ const effectiveEnableDatasets = catalogsEnabled ? true : datasetsEnabled;
7483
7432
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7484
7433
  /* @__PURE__ */ jsxRuntime.jsx(
7485
7434
  QueryHeader,
7486
7435
  {
7487
7436
  db,
7488
7437
  defaultDataset: defaultDataset || "",
7489
- enableDatasets: !db.disableDatasets,
7490
- enableCatalogs: db.disableCatalogs === false,
7438
+ enableDatasets: effectiveEnableDatasets,
7439
+ enableCatalogs: catalogsEnabled,
7491
7440
  onChange: onQueryHeaderChange,
7492
7441
  onRunQuery,
7493
7442
  onQueryRowChange: setQueryRowFilter,
@@ -10157,8 +10106,10 @@ function QueryOptionGroup({ title, children, collapsedInfo, queryStats }) {
10157
10106
  children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.body, children })
10158
10107
  }
10159
10108
  ),
10160
- queryStats && runtime.config.featureToggles.lokiQuerySplitting && /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { content: "Note: the query will be split into multiple parts and executed in sequence. Query limits will only apply each individual part.", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { tabIndex: 0, name: "info-circle", className: styles.tooltip, size: "sm" }) }),
10161
- queryStats && /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles.stats, children: generateQueryStats(queryStats) })
10109
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.queryStatsWrap, children: [
10110
+ queryStats && runtime.config.featureToggles.lokiQuerySplitting && /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { content: "Note: the query will be split into multiple parts and executed in sequence. Query limits will only apply each individual part.", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Icon, { tabIndex: 0, name: "info-circle", className: styles.tooltip, size: "sm" }) }),
10111
+ queryStats && /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles.stats, children: generateQueryStats(queryStats) })
10112
+ ] })
10162
10113
  ] });
10163
10114
  }
10164
10115
  const getStyles = (theme) => {
@@ -10197,6 +10148,13 @@ const getStyles = (theme) => {
10197
10148
  gap: theme.spacing(2),
10198
10149
  flexWrap: "wrap"
10199
10150
  }),
10151
+ queryStatsWrap: css.css({
10152
+ display: "flex",
10153
+ alignItems: "center",
10154
+ alignSelf: "flex-start",
10155
+ label: "query-stats-wrap",
10156
+ padding: theme.spacing(1)
10157
+ }),
10200
10158
  stats: css.css({
10201
10159
  margin: "0px",
10202
10160
  color: theme.colors.text.secondary,
@@ -40517,7 +40475,6 @@ exports.RunQueryButton = RunQueryButton;
40517
40475
  exports.SQLEditor = SQLEditor;
40518
40476
  exports.SQLEditorMode = SQLEditorMode;
40519
40477
  exports.SQLEditorTestUtils = SQLEditorTestUtils;
40520
- exports.SchemaSelector = SchemaSelector;
40521
40478
  exports.SecureSocksProxyToggle = SecureSocksProxyToggle;
40522
40479
  exports.Segment = Segment;
40523
40480
  exports.Space = Space;