@ssa-ui-kit/infra-dash 0.0.2 → 0.1.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.
package/dist/index.js CHANGED
@@ -65,13 +65,16 @@ __webpack_require__.d(__webpack_exports__, {
65
65
  DashboardEditorInternal: () => (/* reexport */ DashboardEditorInternal),
66
66
  DashboardViewer: () => (/* reexport */ DashboardViewer),
67
67
  InfraDashProvider: () => (/* reexport */ InfraDashProvider),
68
+ PeriodSelector: () => (/* reexport */ PeriodSelector),
68
69
  RestInfraDashTransport: () => (/* reexport */ RestInfraDashTransport),
69
70
  useCreateDashboard: () => (/* reexport */ useCreateDashboard),
70
71
  useDashboard: () => (/* reexport */ useDashboard),
71
72
  useDashboards: () => (/* reexport */ useDashboards),
72
73
  useDeleteDashboard: () => (/* reexport */ useDeleteDashboard),
73
74
  useInfraDashContext: () => (/* reexport */ useInfraDashContext),
75
+ useInfraDashPanelDataPeriodContext: () => (/* reexport */ useInfraDashPanelDataPeriodContext),
74
76
  useMutationClient: () => (/* reexport */ useMutationClient),
77
+ usePublishedDashboards: () => (/* reexport */ usePublishedDashboards),
75
78
  useQueryClient: () => (/* reexport */ useQueryClient),
76
79
  useTransport: () => (/* reexport */ useTransport),
77
80
  useUpdateDashboard: () => (/* reexport */ useUpdateDashboard)
@@ -550,7 +553,7 @@ function partialMatchKey(a, b) {
550
553
  }
551
554
  ;// external "@ssa-ui-kit/hooks"
552
555
  const hooks_namespaceObject = require("@ssa-ui-kit/hooks");
553
- ;// ./src/shared/context.ts
556
+ ;// ./src/shared/context/root.ts
554
557
 
555
558
  const [InfraDashInternalProvider, useInfraDashContext] = (0,hooks_namespaceObject.createSafeContext)('useInfraDashContext must be used within a InfraDashProvider');
556
559
  ;// ./src/shared/query/useQuery.ts
@@ -662,6 +665,17 @@ const useDashboard = (dashboardId, options) => {
662
665
  }, queryOptions);
663
666
  return result;
664
667
  };
668
+ const usePublishedDashboards = options => {
669
+ const {
670
+ transport,
671
+ ...queryOptions
672
+ } = options || {};
673
+ const _transport = useTransport(transport);
674
+ const result = useQuery(['dashboards', 'published'], async signal => {
675
+ return await _transport.getPublishedDashboards(signal);
676
+ }, queryOptions);
677
+ return result;
678
+ };
665
679
  const useCreateDashboard = options => {
666
680
  const {
667
681
  transport,
@@ -670,16 +684,18 @@ const useCreateDashboard = options => {
670
684
  const _transport = useTransport(transport);
671
685
  const result = useMutation(['create-dashboard'], async (payload, signal) => {
672
686
  const panels = payload.panels.map(panel => ({
673
- ...panel,
674
- id: panel.panelDefinition.source.panelId
687
+ // for some reason backend accepts stringified JSON but returns object
688
+ panelDefinition: JSON.stringify(panel.panelDefinition),
689
+ source: panel.source
675
690
  }));
676
- const dashboardsUid = new Set(panels.map(panel => panel.panelDefinition.source.dashboardUid));
691
+ const dashboardsUid = new Set(panels.map(panel => panel.source.dashboardUid));
677
692
  if (!dashboardsUid.size) {
678
693
  throw new Error('At least one panel must be provided');
679
694
  }
680
695
  return await _transport.createDashboard({
681
- ...payload,
682
- dashboardUid: dashboardsUid.values().next().value,
696
+ title: payload.title,
697
+ published: payload.published,
698
+ dashboardDefinition: payload.dashboardDefinition,
683
699
  panels
684
700
  }, signal);
685
701
  }, mutationOptions);
@@ -693,15 +709,17 @@ const useUpdateDashboard = (dashboardId, options) => {
693
709
  const _transport = useTransport(transport);
694
710
  const result = useMutation(['update-dashboard', dashboardId], async (payload, signal) => {
695
711
  const panels = payload.panels.map(panel => ({
696
- ...panel,
697
- id: panel.panelDefinition.source.panelId
712
+ panelDefinition: JSON.stringify(panel.panelDefinition),
713
+ source: panel.source
698
714
  }));
699
- const dashboardsUid = new Set(panels.map(panel => panel.panelDefinition.source.dashboardUid));
715
+ const dashboardsUid = new Set(panels.map(panel => panel.source.dashboardUid));
700
716
  if (!dashboardsUid.size) {
701
717
  throw new Error('At least one panel must be provided');
702
718
  }
703
719
  return await _transport.updateDashboard({
704
- ...payload,
720
+ title: payload.title,
721
+ published: payload.published,
722
+ dashboardDefinition: payload.dashboardDefinition,
705
723
  panels,
706
724
  dashboardId
707
725
  }, signal);
@@ -719,6 +737,86 @@ const useDeleteDashboard = (dashboardId, options) => {
719
737
  }, mutationOptions);
720
738
  return result;
721
739
  };
740
+ ;// ./src/shared/panel.ts
741
+ /**
742
+ * Defines the configuration and positioning information for a dashboard panel.
743
+ * Contains both the component configuration and grid layout positioning.
744
+ */
745
+
746
+ /**
747
+ * Represents a complete dashboard panel with its metadata, schema, and definition.
748
+ * Combines panel identity, display information, data schema, and component configuration.
749
+ */
750
+
751
+ /**
752
+ * Optional schema defining the structure of props this component expects.
753
+ * Used for validation and form generation in configuration UIs.
754
+ */
755
+
756
+ /**
757
+ * Configuration object for registering a panel component type.
758
+ * Defines how a specific component should be rendered and what panel types it supports.
759
+ */
760
+
761
+ /**
762
+ * Constant object defining available panel data sources.
763
+ * Currently only supports Grafana as a data source.
764
+ */
765
+ const PANEL_DATA_SOURCE = {
766
+ GRAFANA: 'grafana'
767
+ };
768
+ /**
769
+ * Pattern matching utility function for handling different panel data sources.
770
+ * Provides type-safe way to handle operations based on the data source type.
771
+ *
772
+ * @param source - The panel data source to match against
773
+ * @param handlers - Object containing handler functions for each data source type
774
+ */
775
+ const matchPanelDataSource = (source, handlers) => {
776
+ switch (source) {
777
+ case PANEL_DATA_SOURCE.GRAFANA:
778
+ return handlers.grafana();
779
+ default:
780
+ {
781
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
782
+ const _ = source;
783
+ throw new Error(`Unsupported panel data source: ${source}`);
784
+ }
785
+ }
786
+ };
787
+
788
+ /**
789
+ * Represents panel data with its source and associated data.
790
+ * Currently only supports Grafana as a data source.
791
+ */
792
+
793
+ const PANEL_DATA_PERIOD = {
794
+ LAST_HOUR: 0,
795
+ LAST_6_HOURS: 1,
796
+ LAST_24_HOURS: 2,
797
+ LAST_7_DAYS: 3,
798
+ LAST_30_DAYS: 4
799
+ };
800
+ ;// ./src/shared/context/panelDataPeriod.ts
801
+
802
+
803
+ const useInfraDashPanelDataPeriod = ({
804
+ defaultPeriod,
805
+ period: providedPeriod,
806
+ onPeriodChange
807
+ } = {}) => {
808
+ const [period, changePeriod] = (0,hooks_namespaceObject.useUncontrolled)({
809
+ value: providedPeriod,
810
+ defaultValue: defaultPeriod,
811
+ finalValue: PANEL_DATA_PERIOD.LAST_HOUR,
812
+ onChange: onPeriodChange
813
+ });
814
+ return {
815
+ period,
816
+ changePeriod
817
+ };
818
+ };
819
+ const [InfraDashPanelDataPeriodProvider, useInfraDashPanelDataPeriodContext] = (0,hooks_namespaceObject.createSafeContext)('useInfraDashPanelDataPeriodContext must be used within a InfraDashPanelDataPeriodProvider');
722
820
  ;// external "react-grid-layout"
723
821
  const external_react_grid_layout_namespaceObject = require("react-grid-layout");
724
822
  var external_react_grid_layout_default = /*#__PURE__*/__webpack_require__.n(external_react_grid_layout_namespaceObject);
@@ -782,8 +880,8 @@ function DashboardPanelGrid_EMOTION_STRINGIFIED_CSS_ERROR_() { return "You have
782
880
 
783
881
 
784
882
  var DashboardPanelGrid_ref2 = true ? {
785
- name: "52s4fb",
786
- styles: "width:100%;.react-grid-item.cssTransforms{transition-property:none;}.react-grid-layout{transition:none;}"
883
+ name: "tu5rj9",
884
+ styles: "width:100%;.react-grid-item.cssTransforms{transition-property:none;}.react-grid-layout{transition:none;}.react-grid-item.react-grid-placeholder{background-color:transparent;}"
787
885
  } : 0;
788
886
  var _ref3 = true ? {
789
887
  name: "k9eird",
@@ -816,11 +914,13 @@ const DashboardPanelGrid = ({
816
914
  (0,external_react_namespaceObject.useEffect)(() => {
817
915
  if (refetchIntervalMs) {
818
916
  queryClient.invalidateQueries({
819
- key: ['panel-data']
917
+ key: ['panel-data'],
918
+ type: 'active'
820
919
  });
821
920
  const intervalId = setInterval(() => {
822
921
  queryClient.invalidateQueries({
823
- key: ['panel-data']
922
+ key: ['panel-data'],
923
+ type: 'active'
824
924
  });
825
925
  }, refetchIntervalMs);
826
926
  return () => clearInterval(intervalId);
@@ -908,8 +1008,8 @@ const DashboardPanelGrid = ({
908
1008
  });
909
1009
  };
910
1010
  var DashboardPanelGrid_ref = true ? {
911
- name: "p3gkp4",
912
- styles: ".react-resizable-handle-se{z-index:1;}"
1011
+ name: "ujxn9q",
1012
+ styles: ".react-resizable-handle-se{z-index:1;padding:0;::after{right:0;bottom:0;}}"
913
1013
  } : 0;
914
1014
  const GridItem = /*#__PURE__*/(0,external_react_namespaceObject.forwardRef)(function GridItem({
915
1015
  children,
@@ -929,6 +1029,7 @@ const GridItem = /*#__PURE__*/(0,external_react_namespaceObject.forwardRef)(func
929
1029
 
930
1030
 
931
1031
 
1032
+
932
1033
  const DashboardViewer = ({
933
1034
  dashboard,
934
1035
  dashboardId,
@@ -937,16 +1038,29 @@ const DashboardViewer = ({
937
1038
  const dashboardById = useDashboard(dashboardId ?? -1, {
938
1039
  enabled: !!dashboardId && !dashboard
939
1040
  });
940
- if (dashboard) {
941
- return (0,jsx_runtime_namespaceObject.jsx)(external_react_error_boundary_namespaceObject.ErrorBoundary, {
942
- fallback: (0,jsx_runtime_namespaceObject.jsx)(DashboardError, {
943
- children: "Something went wrong"
944
- }),
945
- children: (0,jsx_runtime_namespaceObject.jsx)(DashboardPanelGrid, {
946
- ...props,
947
- dashboard: dashboard
1041
+ const DashboardWrapper = ({
1042
+ dashboard
1043
+ }) => {
1044
+ const panelDataPeriod = useInfraDashPanelDataPeriod({
1045
+ ...props
1046
+ });
1047
+ return (0,jsx_runtime_namespaceObject.jsx)(InfraDashPanelDataPeriodProvider, {
1048
+ value: panelDataPeriod,
1049
+ children: (0,jsx_runtime_namespaceObject.jsx)(external_react_error_boundary_namespaceObject.ErrorBoundary, {
1050
+ fallback: (0,jsx_runtime_namespaceObject.jsx)(DashboardError, {
1051
+ children: "Something went wrong"
1052
+ }),
1053
+ children: (0,jsx_runtime_namespaceObject.jsx)(DashboardPanelGrid, {
1054
+ ...props,
1055
+ dashboard: dashboard
1056
+ })
948
1057
  })
949
1058
  });
1059
+ };
1060
+ if (dashboard) {
1061
+ return (0,jsx_runtime_namespaceObject.jsx)(DashboardWrapper, {
1062
+ dashboard: dashboard
1063
+ });
950
1064
  }
951
1065
  if (!dashboardById.isLoaded) {
952
1066
  return (0,jsx_runtime_namespaceObject.jsx)(LoadingDashboard, {});
@@ -954,18 +1068,37 @@ const DashboardViewer = ({
954
1068
  if (dashboardById.error) {
955
1069
  return (0,jsx_runtime_namespaceObject.jsx)(DashboardError, {});
956
1070
  }
957
- return (0,jsx_runtime_namespaceObject.jsx)(external_react_error_boundary_namespaceObject.ErrorBoundary, {
958
- fallback: (0,jsx_runtime_namespaceObject.jsx)(DashboardError, {
959
- children: "Something went wrong"
960
- }),
961
- children: (0,jsx_runtime_namespaceObject.jsx)(DashboardPanelGrid, {
962
- ...props,
963
- dashboard: dashboardById.data
964
- })
1071
+ return (0,jsx_runtime_namespaceObject.jsx)(DashboardWrapper, {
1072
+ dashboard: dashboardById.data
965
1073
  });
966
1074
  };
967
1075
  ;// ./src/widgets/DashboardViewer/index.ts
968
1076
 
1077
+ ;// ./src/components/PeriodSelector/PeriodSelector.tsx
1078
+
1079
+
1080
+
1081
+
1082
+ const PeriodSelector = () => {
1083
+ const {
1084
+ period,
1085
+ changePeriod
1086
+ } = useInfraDashPanelDataPeriodContext();
1087
+ const handlePeriodSelect = period => {
1088
+ changePeriod(period);
1089
+ };
1090
+ const options = [[PANEL_DATA_PERIOD.LAST_HOUR, 'Last Hour'], [PANEL_DATA_PERIOD.LAST_6_HOURS, 'Last 6 Hours'], [PANEL_DATA_PERIOD.LAST_24_HOURS, 'Last 24 Hours'], [PANEL_DATA_PERIOD.LAST_7_DAYS, 'Last 7 Days'], [PANEL_DATA_PERIOD.LAST_30_DAYS, 'Last 30 Days']];
1091
+ return (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Typeahead, {
1092
+ filterOptions: false,
1093
+ selectedItems: [period],
1094
+ onChange: componentId => handlePeriodSelect(componentId),
1095
+ children: options.map(([value, label]) => (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.TypeaheadOption, {
1096
+ value: value,
1097
+ label: label,
1098
+ children: label
1099
+ }, value))
1100
+ });
1101
+ };
969
1102
  ;// ./src/shared/icons/DashboardIcon.tsx
970
1103
 
971
1104
  const DashboardIcon = ({
@@ -987,58 +1120,6 @@ const DashboardIcon = ({
987
1120
  fill: fill
988
1121
  })]
989
1122
  });
990
- ;// ./src/shared/panel.ts
991
- /**
992
- * Defines the configuration and positioning information for a dashboard panel.
993
- * Contains both the component configuration and grid layout positioning.
994
- */
995
-
996
- /**
997
- * Represents a complete dashboard panel with its metadata, schema, and definition.
998
- * Combines panel identity, display information, data schema, and component configuration.
999
- */
1000
-
1001
- /**
1002
- * Optional schema defining the structure of props this component expects.
1003
- * Used for validation and form generation in configuration UIs.
1004
- */
1005
-
1006
- /**
1007
- * Configuration object for registering a panel component type.
1008
- * Defines how a specific component should be rendered and what panel types it supports.
1009
- */
1010
-
1011
- /**
1012
- * Constant object defining available panel data sources.
1013
- * Currently only supports Grafana as a data source.
1014
- */
1015
- const PANEL_DATA_SOURCE = {
1016
- GRAFANA: 'grafana'
1017
- };
1018
- /**
1019
- * Pattern matching utility function for handling different panel data sources.
1020
- * Provides type-safe way to handle operations based on the data source type.
1021
- *
1022
- * @param source - The panel data source to match against
1023
- * @param handlers - Object containing handler functions for each data source type
1024
- */
1025
- const matchPanelDataSource = (source, handlers) => {
1026
- switch (source) {
1027
- case PANEL_DATA_SOURCE.GRAFANA:
1028
- return handlers.grafana();
1029
- default:
1030
- {
1031
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1032
- const _ = source;
1033
- throw new Error(`Unsupported panel data source: ${source}`);
1034
- }
1035
- }
1036
- };
1037
-
1038
- /**
1039
- * Represents panel data with its source and associated data.
1040
- * Currently only supports Grafana as a data source.
1041
- */
1042
1123
  ;// ./src/widgets/DashboardEditor/components/DashboardSelectorDrawer.tsx
1043
1124
  function DashboardSelectorDrawer_EMOTION_STRINGIFIED_CSS_ERROR_() { return "You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."; }
1044
1125
 
@@ -1046,8 +1127,8 @@ function DashboardSelectorDrawer_EMOTION_STRINGIFIED_CSS_ERROR_() { return "You
1046
1127
 
1047
1128
 
1048
1129
  var DashboardSelectorDrawer_ref = true ? {
1049
- name: "1gk49vx",
1050
- styles: "width:400px;padding:24px 32px"
1130
+ name: "u5gcpt",
1131
+ styles: "width:400px;padding:24px 32px;z-index:10"
1051
1132
  } : 0;
1052
1133
  var DashboardSelectorDrawer_ref2 = true ? {
1053
1134
  name: "13udsys",
@@ -1123,8 +1204,8 @@ function PanelSettingsDrawer_EMOTION_STRINGIFIED_CSS_ERROR_() { return "You have
1123
1204
 
1124
1205
 
1125
1206
  var PanelSettingsDrawer_ref = true ? {
1126
- name: "1c73qam",
1127
- styles: "max-width:400px;padding:24px 32px"
1207
+ name: "12ld9rx",
1208
+ styles: "max-width:400px;padding:24px 32px;z-index:10"
1128
1209
  } : 0;
1129
1210
  var PanelSettingsDrawer_ref2 = true ? {
1130
1211
  name: "1d3w5wq",
@@ -1210,6 +1291,7 @@ function ExternalDashboardsList_EMOTION_STRINGIFIED_CSS_ERROR_() { return "You h
1210
1291
 
1211
1292
 
1212
1293
 
1294
+
1213
1295
  var ExternalDashboardsList_ref = true ? {
1214
1296
  name: "tc4e7",
1215
1297
  styles: "justify-content:center;height:100%;padding:8px"
@@ -1224,14 +1306,13 @@ var ExternalDashboardsList_ref3 = true ? {
1224
1306
  } : 0;
1225
1307
  const ExternalPanelList = ({
1226
1308
  dashboard,
1309
+ panels,
1310
+ isLoaded,
1311
+ error,
1227
1312
  onPanelClick
1228
1313
  }) => {
1229
1314
  const theme = (0,react_namespaceObject.useTheme)();
1230
- const {
1231
- panelRegistry
1232
- } = useInfraDashContext();
1233
- const externalPanels = useGrafanaPanels(dashboard.id);
1234
- if (!externalPanels.isLoaded) {
1315
+ if (!isLoaded) {
1235
1316
  return (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Wrapper, {
1236
1317
  direction: "column",
1237
1318
  css: ExternalDashboardsList_ref,
@@ -1253,7 +1334,7 @@ const ExternalPanelList = ({
1253
1334
  })
1254
1335
  });
1255
1336
  }
1256
- if (externalPanels.error) {
1337
+ if (error) {
1257
1338
  return (0,jsx_runtime_namespaceObject.jsxs)(core_namespaceObject.Wrapper, {
1258
1339
  direction: "column",
1259
1340
  css: ExternalDashboardsList_ref2,
@@ -1262,7 +1343,7 @@ const ExternalPanelList = ({
1262
1343
  })]
1263
1344
  });
1264
1345
  }
1265
- if (!externalPanels.data.length) {
1346
+ if (!panels.length) {
1266
1347
  return (0,jsx_runtime_namespaceObject.jsxs)(core_namespaceObject.Wrapper, {
1267
1348
  direction: "column",
1268
1349
  css: ExternalDashboardsList_ref3,
@@ -1271,15 +1352,8 @@ const ExternalPanelList = ({
1271
1352
  })]
1272
1353
  });
1273
1354
  }
1274
- const availablePanels = externalPanels.data.filter(panel => {
1275
- if (!panel.panelSchema?.type) {
1276
- return false;
1277
- }
1278
- const availableComponents = panelRegistry.findPanelConfigsByType(panel.panelSchema.type);
1279
- return availableComponents.length > 0;
1280
- });
1281
1355
  return (0,jsx_runtime_namespaceObject.jsx)(jsx_runtime_namespaceObject.Fragment, {
1282
- children: availablePanels.map(panel => (0,jsx_runtime_namespaceObject.jsxs)(core_namespaceObject.Button, {
1356
+ children: panels.map(panel => (0,jsx_runtime_namespaceObject.jsxs)(core_namespaceObject.Button, {
1283
1357
  variant: "tertiary",
1284
1358
  className: /*#__PURE__*/(0,css_namespaceObject.css)("width:100%;min-height:34px;gap:8px;padding:8px 14px 8px 34px!important;justify-content:space-between;text-align:left;& svg{& path{stroke:", theme.colors.greyDarker, ";stroke-width:1.4px;}}" + ( true ? "" : 0), true ? "" : 0),
1285
1359
  onClick: () => onPanelClick?.(dashboard, panel),
@@ -1290,6 +1364,75 @@ const ExternalPanelList = ({
1290
1364
  }, panel.id))
1291
1365
  });
1292
1366
  };
1367
+ const DashboardAccordionItem = ({
1368
+ dashboard,
1369
+ search,
1370
+ onPanelClick,
1371
+ ...accordionProps
1372
+ }) => {
1373
+ const theme = (0,react_namespaceObject.useTheme)();
1374
+ const {
1375
+ panelRegistry
1376
+ } = useInfraDashContext();
1377
+ const panelsQuery = useGrafanaPanels(dashboard.id);
1378
+ const loadedPanels = panelsQuery.data ?? [];
1379
+ const availablePanels = loadedPanels.filter(panel => {
1380
+ if (!panel.panelSchema?.type) {
1381
+ return false;
1382
+ }
1383
+ if (search && !panel.title.toLowerCase().includes(search.toLowerCase())) {
1384
+ return false;
1385
+ }
1386
+ const availableComponents = panelRegistry.findPanelConfigsByType(panel.panelSchema.type);
1387
+ return availableComponents.length > 0;
1388
+ });
1389
+ if (search && panelsQuery.isLoaded && !availablePanels.length) {
1390
+ return null;
1391
+ }
1392
+ return (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Accordion, {
1393
+ id: dashboard.id,
1394
+ title: dashboard.title,
1395
+ className: /*#__PURE__*/(0,css_namespaceObject.css)( true ? {
1396
+ name: "2zzvc7",
1397
+ styles: "padding:0!important;align-items:start!important"
1398
+ } : 0),
1399
+ renderTitle: ({
1400
+ title,
1401
+ isOpened,
1402
+ onClick
1403
+ }) => (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Button, {
1404
+ onClick: onClick,
1405
+ variant: "tertiary",
1406
+ className: /*#__PURE__*/(0,css_namespaceObject.css)("width:100%;min-height:34px;gap:8px;padding:8px 14px!important;text-align:left;& svg{& path{stroke:", theme.colors.greyDarker, ";stroke-width:1.4px;}}" + ( true ? "" : 0), true ? "" : 0),
1407
+ startIcon: isOpened ? (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Icon, {
1408
+ name: "carrot-down",
1409
+ size: 12
1410
+ }) : (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Icon, {
1411
+ name: "carrot-right",
1412
+ size: 12
1413
+ }),
1414
+ children: title
1415
+ }),
1416
+ renderContent: ({
1417
+ isOpened
1418
+ }) => (0,jsx_runtime_namespaceObject.jsx)("div", {
1419
+ css: /*#__PURE__*/(0,react_namespaceObject.css)({
1420
+ width: '100%',
1421
+ display: isOpened ? 'block' : 'none',
1422
+ fontWeight: 500,
1423
+ fontSize: '14px'
1424
+ }, true ? "" : 0, true ? "" : 0),
1425
+ children: (0,jsx_runtime_namespaceObject.jsx)(ExternalPanelList, {
1426
+ panels: availablePanels,
1427
+ isLoaded: panelsQuery.isLoaded,
1428
+ error: panelsQuery.error,
1429
+ dashboard: dashboard,
1430
+ onPanelClick: onPanelClick
1431
+ })
1432
+ }),
1433
+ ...accordionProps
1434
+ }, dashboard.id);
1435
+ };
1293
1436
  var _ref4 = true ? {
1294
1437
  name: "67cb9k",
1295
1438
  styles: "justify-content:center;height:100%"
@@ -1303,14 +1446,19 @@ var _ref6 = true ? {
1303
1446
  styles: "justify-content:center;height:100%"
1304
1447
  } : 0;
1305
1448
  var _ref7 = true ? {
1306
- name: "1qmr6ab",
1307
- styles: "overflow:auto"
1449
+ name: "1d0nbku",
1450
+ styles: "margin-top:24px"
1451
+ } : 0;
1452
+ var _ref8 = true ? {
1453
+ name: "1yghct1",
1454
+ styles: "overflow:auto;width:100%"
1308
1455
  } : 0;
1309
1456
  const ExternalDashboardsList = ({
1310
1457
  onPanelClick,
1311
1458
  ...divProps
1312
1459
  }) => {
1313
1460
  const theme = (0,react_namespaceObject.useTheme)();
1461
+ const [search, setSearch] = (0,external_react_namespaceObject.useState)('');
1314
1462
  const dashboardsQuery = useGrafanaDashboards();
1315
1463
  if (!dashboardsQuery.isLoaded) {
1316
1464
  return (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Wrapper, {
@@ -1355,51 +1503,30 @@ const ExternalDashboardsList = ({
1355
1503
  })]
1356
1504
  });
1357
1505
  }
1358
- return (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.AccordionGroupContextProvider, {
1359
- children: (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.AccordionGroup, {
1360
- size: "small",
1361
- css: _ref7,
1362
- ...divProps,
1363
- children: dashboardsQuery.data.map(dashboard => (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Accordion, {
1364
- id: dashboard.id,
1365
- title: dashboard.title,
1366
- className: /*#__PURE__*/(0,css_namespaceObject.css)( true ? {
1367
- name: "2zzvc7",
1368
- styles: "padding:0!important;align-items:start!important"
1369
- } : 0),
1370
- renderTitle: ({
1371
- title,
1372
- isOpened,
1373
- onClick
1374
- }) => (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Button, {
1375
- onClick: onClick,
1376
- variant: "tertiary",
1377
- className: /*#__PURE__*/(0,css_namespaceObject.css)("width:100%;min-height:34px;gap:8px;padding:8px 14px!important;text-align:left;& svg{& path{stroke:", theme.colors.greyDarker, ";stroke-width:1.4px;}}" + ( true ? "" : 0), true ? "" : 0),
1378
- startIcon: isOpened ? (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Icon, {
1379
- name: "carrot-down",
1380
- size: 12
1381
- }) : (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Icon, {
1382
- name: "carrot-right",
1383
- size: 12
1384
- }),
1385
- children: title
1386
- }),
1387
- renderContent: ({
1388
- isOpened
1389
- }) => (0,jsx_runtime_namespaceObject.jsx)("div", {
1390
- css: /*#__PURE__*/(0,react_namespaceObject.css)({
1391
- width: '100%',
1392
- display: isOpened ? 'block' : 'none',
1393
- fontWeight: 500,
1394
- fontSize: '14px'
1395
- }, true ? "" : 0, true ? "" : 0),
1396
- children: (0,jsx_runtime_namespaceObject.jsx)(ExternalPanelList, {
1397
- dashboard: dashboard,
1398
- onPanelClick: onPanelClick
1399
- })
1400
- })
1401
- }, dashboard.id))
1402
- })
1506
+ return (0,jsx_runtime_namespaceObject.jsxs)(jsx_runtime_namespaceObject.Fragment, {
1507
+ children: [(0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Input, {
1508
+ name: "panel-search",
1509
+ placeholder: "Search...",
1510
+ inputProps: {
1511
+ value: search,
1512
+ onChange: e => setSearch(e.target.value)
1513
+ },
1514
+ css: _ref7
1515
+ }), (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.AccordionGroupContextProvider, {
1516
+ children: (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.AccordionGroup, {
1517
+ size: "small",
1518
+ css: _ref8,
1519
+ ...divProps,
1520
+ children: dashboardsQuery.data.map(dashboard => (0,jsx_runtime_namespaceObject.jsx)(DashboardAccordionItem
1521
+ // id is required by AccordionGroup logic
1522
+ , {
1523
+ id: dashboard.id,
1524
+ dashboard: dashboard,
1525
+ search: search,
1526
+ onPanelClick: onPanelClick
1527
+ }, dashboard.id))
1528
+ })
1529
+ })]
1403
1530
  });
1404
1531
  };
1405
1532
  ;// ./src/widgets/DashboardEditor/helpers.ts
@@ -1428,13 +1555,13 @@ const appendPanel = params => {
1428
1555
  const newPanel = {
1429
1556
  id: -Date.now(),
1430
1557
  // use a negative ID to indicate a new panel
1558
+ source: {
1559
+ type: 'grafana',
1560
+ dashboardUid: grafanaDashboard.id,
1561
+ panelId: grafanaPanel.id
1562
+ },
1431
1563
  panelDefinition: {
1432
1564
  version: 1,
1433
- source: {
1434
- type: 'grafana',
1435
- dashboardUid: grafanaDashboard.id,
1436
- panelId: grafanaPanel.id
1437
- },
1438
1565
  component: {
1439
1566
  id: defaultComponentConfig.componentId,
1440
1567
  props: {}
@@ -1489,20 +1616,36 @@ const applyNewLayout = ({
1489
1616
  }) => {
1490
1617
  const newLayoutMap = newLayout.reduce((map, {
1491
1618
  i,
1492
- ...layout
1619
+ x,
1620
+ y,
1621
+ w,
1622
+ h
1493
1623
  }) => ({
1494
1624
  ...map,
1495
- [i]: layout
1496
- }), {});
1497
- dashboard.panels.forEach(panel => {
1498
- const newGridPos = newLayoutMap[panel.id.toString()];
1499
- if (!newGridPos) {
1500
- throw new Error(`New position for the ${panel.id} not fount`);
1625
+ [i]: {
1626
+ x,
1627
+ y,
1628
+ w,
1629
+ h
1501
1630
  }
1502
- panel.panelDefinition.gridPos = newGridPos;
1503
- return panel;
1504
- });
1505
- return dashboard;
1631
+ }), {});
1632
+ const newDashboard = {
1633
+ ...dashboard,
1634
+ panels: dashboard.panels.map(panel => {
1635
+ const newGridPos = newLayoutMap[panel.id.toString()];
1636
+ if (!newGridPos) {
1637
+ throw new Error(`New position for the panel ${panel.id} not found`);
1638
+ }
1639
+ return {
1640
+ ...panel,
1641
+ panelDefinition: {
1642
+ ...panel.panelDefinition,
1643
+ gridPos: newGridPos
1644
+ }
1645
+ };
1646
+ })
1647
+ };
1648
+ return newDashboard;
1506
1649
  };
1507
1650
  ;// ./src/widgets/DashboardEditor/components/PanelControl.tsx
1508
1651
  function PanelControl_EMOTION_STRINGIFIED_CSS_ERROR_() { return "You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."; }
@@ -1563,10 +1706,15 @@ const PanelControlContent = ({
1563
1706
  })]
1564
1707
  });
1565
1708
  };
1709
+ var PanelControl_ref3 = true ? {
1710
+ name: "1jyo0em",
1711
+ styles: "margin-right:5px;margin-top:5px"
1712
+ } : 0;
1566
1713
  const PanelControl = props => {
1567
1714
  return (0,jsx_runtime_namespaceObject.jsxs)(core_namespaceObject.Popover, {
1568
1715
  children: [(0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.PopoverTrigger, {
1569
1716
  variant: "tertiary",
1717
+ css: PanelControl_ref3,
1570
1718
  children: (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Icon, {
1571
1719
  name: "more-vertical",
1572
1720
  size: 14
@@ -1716,6 +1864,7 @@ function DashboardEditor_EMOTION_STRINGIFIED_CSS_ERROR_() { return "You have tri
1716
1864
 
1717
1865
 
1718
1866
 
1867
+
1719
1868
  var DashboardEditor_ref = true ? {
1720
1869
  name: "1st9kbp",
1721
1870
  styles: "height:100%;position:relative"
@@ -1744,7 +1893,7 @@ var DashboardEditor_ref7 = true ? {
1744
1893
  name: "1lsto0t",
1745
1894
  styles: "max-width:250px"
1746
1895
  } : 0;
1747
- var _ref8 = true ? {
1896
+ var DashboardEditor_ref8 = true ? {
1748
1897
  name: "1yxfaqj",
1749
1898
  styles: "height:46px"
1750
1899
  } : 0;
@@ -1784,6 +1933,7 @@ const DashboardEditorInternal = ({
1784
1933
  },
1785
1934
  id: -1,
1786
1935
  panels: [],
1936
+ published: false,
1787
1937
  title: 'New Dashboard'
1788
1938
  },
1789
1939
  onChange
@@ -1840,12 +1990,7 @@ const DashboardEditorInternal = ({
1840
1990
  if (dashboard.id > 0) {
1841
1991
  updateDashboard(dashboard).then(() => onSaved?.(dashboard)).catch(error => onError?.(error));
1842
1992
  } else {
1843
- createDashboard({
1844
- panels: dashboard.panels,
1845
- dashboardDefinition: dashboard.dashboardDefinition,
1846
- title: dashboard.title,
1847
- dashboardUid: dashboard.id.toString()
1848
- }).then(() => onCreate?.()).catch(error => onError?.(error));
1993
+ createDashboard(dashboard).then(() => onCreate?.()).catch(error => onError?.(error));
1849
1994
  }
1850
1995
  };
1851
1996
  const selectedPanel = selectedPanelId !== null ? dashboard.panels.find(p => p.id === selectedPanelId) : null;
@@ -1885,9 +2030,16 @@ const DashboardEditorInternal = ({
1885
2030
  })
1886
2031
  },
1887
2032
  css: DashboardEditor_ref7
1888
- }), (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Button, {
2033
+ }), (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Checkbox, {
2034
+ text: "Publish",
2035
+ initialState: dashboard.published,
2036
+ onChange: published => setDashboard({
2037
+ ...dashboard,
2038
+ published
2039
+ })
2040
+ }), (0,jsx_runtime_namespaceObject.jsx)(PeriodSelector, {}), (0,jsx_runtime_namespaceObject.jsx)(core_namespaceObject.Button, {
1889
2041
  variant: "info",
1890
- css: _ref8,
2042
+ css: DashboardEditor_ref8,
1891
2043
  isDisabled: cannotPersist,
1892
2044
  onClick: handlePersistDashboard,
1893
2045
  children: dashboard.id > 0 ? 'Save' : 'Create'
@@ -1928,15 +2080,26 @@ const DashboardEditor = ({
1928
2080
  const dashboardById = useDashboard(dashboardId ?? -1, {
1929
2081
  enabled: !!dashboardId && !dashboard && !defaultDashboard
1930
2082
  });
1931
- if (!dashboardId) {
1932
- return (0,jsx_runtime_namespaceObject.jsx)(external_react_error_boundary_namespaceObject.ErrorBoundary, {
1933
- fallback: (0,jsx_runtime_namespaceObject.jsx)(DashboardError, {
1934
- children: "Something went wrong"
1935
- }),
1936
- children: (0,jsx_runtime_namespaceObject.jsx)(DashboardEditorInternal, {
1937
- ...props
2083
+ const DashboardWrapper = editorProps => {
2084
+ const panelDataPeriod = useInfraDashPanelDataPeriod({
2085
+ ...props
2086
+ });
2087
+ return (0,jsx_runtime_namespaceObject.jsx)(InfraDashPanelDataPeriodProvider, {
2088
+ value: panelDataPeriod,
2089
+ children: (0,jsx_runtime_namespaceObject.jsx)(external_react_error_boundary_namespaceObject.ErrorBoundary, {
2090
+ fallback: (0,jsx_runtime_namespaceObject.jsx)(DashboardError, {
2091
+ children: "Something went wrong"
2092
+ }),
2093
+ children: (0,jsx_runtime_namespaceObject.jsx)(DashboardEditorInternal, {
2094
+ ...editorProps
2095
+ })
1938
2096
  })
1939
2097
  });
2098
+ };
2099
+ if (!dashboardId) {
2100
+ return (0,jsx_runtime_namespaceObject.jsx)(DashboardWrapper, {
2101
+ ...props
2102
+ });
1940
2103
  }
1941
2104
  if (!dashboardById.isLoaded) {
1942
2105
  return (0,jsx_runtime_namespaceObject.jsx)(LoadingDashboard, {});
@@ -1944,14 +2107,9 @@ const DashboardEditor = ({
1944
2107
  if (dashboardById.error) {
1945
2108
  return (0,jsx_runtime_namespaceObject.jsx)(DashboardError, {});
1946
2109
  }
1947
- return (0,jsx_runtime_namespaceObject.jsx)(external_react_error_boundary_namespaceObject.ErrorBoundary, {
1948
- fallback: (0,jsx_runtime_namespaceObject.jsx)(DashboardError, {
1949
- children: "Something went wrong"
1950
- }),
1951
- children: (0,jsx_runtime_namespaceObject.jsx)(DashboardEditorInternal, {
1952
- ...props,
1953
- defaultDashboard: dashboardById.data
1954
- })
2110
+ return (0,jsx_runtime_namespaceObject.jsx)(DashboardWrapper, {
2111
+ ...props,
2112
+ defaultDashboard: dashboardById.data
1955
2113
  });
1956
2114
  };
1957
2115
  ;// ./src/widgets/DashboardEditor/index.ts
@@ -2023,23 +2181,24 @@ class RestInfraDashTransport {
2023
2181
  }
2024
2182
  async getGrafanaPanelData({
2025
2183
  dashboardUid,
2026
- panelId
2184
+ panelId,
2185
+ period
2027
2186
  }, signal) {
2028
- const request = new Request(this.getUrl(`/grafana/dashboards/${dashboardUid}/panel/${panelId}`), {
2187
+ const request = new Request(this.getUrl(`/grafana/dashboards/${dashboardUid}/panel/${panelId}?period=${period ?? 0}`), {
2029
2188
  method: 'POST',
2030
2189
  signal
2031
2190
  });
2032
2191
  return await this.makeRequest(request);
2033
2192
  }
2034
- async getPanelData(panelId, signal) {
2035
- const request = new Request(this.getUrl(`/dashboards/panels/${panelId}`), {
2036
- method: 'POST',
2193
+ async getDashboards(signal) {
2194
+ const request = new Request(this.getUrl(`/dashboards`), {
2195
+ method: 'GET',
2037
2196
  signal
2038
2197
  });
2039
2198
  return await this.makeRequest(request);
2040
2199
  }
2041
- async getDashboards(signal) {
2042
- const request = new Request(this.getUrl(`/dashboards`), {
2200
+ async getPublishedDashboards(signal) {
2201
+ const request = new Request(this.getUrl(`/dashboards/published`), {
2043
2202
  method: 'GET',
2044
2203
  signal
2045
2204
  });
@@ -2090,6 +2249,8 @@ class RestInfraDashTransport {
2090
2249
 
2091
2250
 
2092
2251
 
2252
+ ;// ./src/components/PeriodSelector/index.ts
2253
+
2093
2254
  ;// ./src/shared/query/query.ts
2094
2255
 
2095
2256
  class QueryEntry {
@@ -2117,6 +2278,9 @@ class QueryEntry {
2117
2278
  }
2118
2279
  });
2119
2280
  }
2281
+ isActive() {
2282
+ return this.subscribers.size && this.options.enabled;
2283
+ }
2120
2284
  updateEntity(fetcher, options) {
2121
2285
  this.fetcher = fetcher;
2122
2286
  this.options = {
@@ -2243,10 +2407,17 @@ class QueryClient {
2243
2407
  invalidateQueries({
2244
2408
  key,
2245
2409
  exact,
2246
- reset
2410
+ reset,
2411
+ type = 'all'
2247
2412
  }) {
2248
2413
  const matchingEntries = [];
2249
2414
  for (const [hash, entry] of this.cache.entries()) {
2415
+ if (type !== 'all') {
2416
+ const active = entry.isActive();
2417
+ if (type === 'active' && !active || type === 'inactive' && active) {
2418
+ continue; // skip entries that don't match the type
2419
+ }
2420
+ }
2250
2421
  if (exact) {
2251
2422
  if (hash === hashKey(key)) {
2252
2423
  matchingEntries.push(entry);
@@ -2462,10 +2633,17 @@ const LoadingPanel = ({
2462
2633
 
2463
2634
 
2464
2635
 
2636
+
2465
2637
  const usePanelData = (panel, options = {}) => {
2466
2638
  const _transport = useTransport(options?.transport);
2467
- const panelSource = panel.panelDefinition.source;
2468
- const result = useQuery(['panel-data', panelSource], async signal => {
2639
+ const {
2640
+ period
2641
+ } = useInfraDashPanelDataPeriodContext();
2642
+ const panelSource = panel.source;
2643
+ const result = useQuery(['panel-data', {
2644
+ panelSource,
2645
+ period
2646
+ }], async signal => {
2469
2647
  if (panelSource.type === PANEL_DATA_SOURCE.GRAFANA) {
2470
2648
  const {
2471
2649
  dashboardUid,
@@ -2473,7 +2651,8 @@ const usePanelData = (panel, options = {}) => {
2473
2651
  } = panelSource;
2474
2652
  const data = await _transport.getGrafanaPanelData({
2475
2653
  dashboardUid,
2476
- panelId
2654
+ panelId,
2655
+ period
2477
2656
  }, signal);
2478
2657
  return {
2479
2658
  source: PANEL_DATA_SOURCE.GRAFANA,
@@ -2580,7 +2759,8 @@ const grafanaDataAdapter = ({
2580
2759
  const TimeseriesPanel = ({
2581
2760
  panel,
2582
2761
  panelData,
2583
- title: providedTitle
2762
+ title: providedTitle,
2763
+ xAxisHoverFormat
2584
2764
  }) => {
2585
2765
  const {
2586
2766
  ref,
@@ -2618,7 +2798,8 @@ const TimeseriesPanel = ({
2618
2798
  r: 50
2619
2799
  },
2620
2800
  xaxis: {
2621
- tickmode: 'auto'
2801
+ tickmode: 'auto',
2802
+ hoverformat: xAxisHoverFormat
2622
2803
  },
2623
2804
  yaxis2: {
2624
2805
  ticksuffix: valueSuffix,
@@ -2641,6 +2822,11 @@ const panelConfig = {
2641
2822
  title: {
2642
2823
  type: 'string',
2643
2824
  title: 'Panel Title'
2825
+ },
2826
+ xAxisHoverFormat: {
2827
+ type: 'string',
2828
+ title: 'X Axis Hover Format',
2829
+ default: '%H:%M, %d %b'
2644
2830
  }
2645
2831
  }
2646
2832
  },
@@ -2648,6 +2834,10 @@ const panelConfig = {
2648
2834
  title: {
2649
2835
  'ui:help': 'Override the default panel title',
2650
2836
  'ui:placeholder': 'Panel Title'
2837
+ },
2838
+ xAxisHoverFormat: {
2839
+ 'ui:help': 'Format for the x-axis hover tooltip',
2840
+ 'ui:placeholder': 'X Axis Hover Format (e.g., %H:%M, %d %b)'
2651
2841
  }
2652
2842
  }
2653
2843
  };
@@ -2964,6 +3154,7 @@ const InfraDashProvider = ({
2964
3154
 
2965
3155
 
2966
3156
 
3157
+
2967
3158
  /******/ return __webpack_exports__;
2968
3159
  /******/ })()
2969
3160
  ;