diff --git a/.github/workflows/release_cli_and_assets.yml b/.github/workflows/release_cli_and_assets.yml
index e6f0fcb92..fd4ef7dc2 100644
--- a/.github/workflows/release_cli_and_assets.yml
+++ b/.github/workflows/release_cli_and_assets.yml
@@ -156,6 +156,7 @@ jobs:
yarn build
env:
REACT_APP_HEAP_ID: ${{ secrets.HEAP_ANALYTICS_PRODUCTION_ID }}
+ REACT_APP_VERSION: ${{ env.VERSION }}
- name: Move Build Assets
run: |-
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 336e9fd45..76cfb3c89 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,14 @@ _What's new?_
* Add support for visualisations of your data with graphs, with easily composable data structures using nodes and edges. ([tbd])
* Improved dashboard UI panel controls for quicker access to common tasks such as downloading panel data. ([#2510](https://github.com/turbot/steampipe/issues/2510), [#2663](https://github.com/turbot/steampipe/issues/2663))
+## v0.17.1 [tbd]
+_Bug fixes_
+* Fix query command `--export` flag raising an error that it cannot be used in interactive mode, even when not in interactive mode. ([#2707](https://github.com/turbot/steampipe/issues/2707))
+* Fix RefreshConnections sometimes storing an unset plugin ModTime property in the connection state file. This leads to failure to refresh connections when plugin has been rebuilt or updated. ([#2721](https://github.com/turbot/steampipe/issues/2721))
+* Fix dashboard text inputs being editable in snapshot mode. ([#2717](https://github.com/turbot/steampipe/issues/2717))
+* Fix dashboard JSONB columns in CSV data downloads not serialising correctly. ([#2733](https://github.com/turbot/steampipe/issues/2733))
+* Add dashboard error modal when users are running a different UI and CLI version ([#2728](https://github.com/turbot/steampipe/issues/2728))
+
## v0.17.0 [2022-11-08]
_What's new?_
diff --git a/pkg/dashboard/dashboardserver/payload.go b/pkg/dashboard/dashboardserver/payload.go
index f40a03a8a..4c714d38e 100644
--- a/pkg/dashboard/dashboardserver/payload.go
+++ b/pkg/dashboard/dashboardserver/payload.go
@@ -10,6 +10,7 @@ import (
"github.com/turbot/steampipe/pkg/dashboard/dashboardexecute"
"github.com/turbot/steampipe/pkg/steampipeconfig"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
+ "github.com/turbot/steampipe/pkg/version"
)
func buildDashboardMetadataPayload(workspaceResources *modconfig.ResourceMaps, cloudMetadata *steampipeconfig.CloudMetadata) ([]byte, error) {
@@ -29,6 +30,9 @@ func buildDashboardMetadataPayload(workspaceResources *modconfig.ResourceMaps, c
payload := DashboardMetadataPayload{
Action: "dashboard_metadata",
Metadata: DashboardMetadata{
+ CLI: DashboardCLIMetadata{
+ Version: version.VersionString,
+ },
InstalledMods: installedMods,
Telemetry: viper.GetString(constants.ArgTelemetry),
},
diff --git a/pkg/dashboard/dashboardserver/types.go b/pkg/dashboard/dashboardserver/types.go
index dac72b51f..93d29777b 100644
--- a/pkg/dashboard/dashboardserver/types.go
+++ b/pkg/dashboard/dashboardserver/types.go
@@ -147,9 +147,14 @@ type ModDashboardMetadata struct {
ShortName string `json:"short_name"`
}
+type DashboardCLIMetadata struct {
+ Version string `json:"version,omitempty"`
+}
+
type DashboardMetadata struct {
Mod *ModDashboardMetadata `json:"mod,omitempty"`
InstalledMods map[string]ModDashboardMetadata `json:"installed_mods,omitempty"`
+ CLI DashboardCLIMetadata `json:"cli"`
Cloud *steampipeconfig.CloudMetadata `json:"cloud,omitempty"`
Telemetry string `json:"telemetry"`
}
diff --git a/ui/dashboard/package.json b/ui/dashboard/package.json
index 798c6fa05..86b94c7fe 100644
--- a/ui/dashboard/package.json
+++ b/ui/dashboard/package.json
@@ -45,6 +45,7 @@
"react-use-websocket": "4.2.0",
"reactflow": "11.2.0",
"remark-gfm": "3.0.1",
+ "semver": "7.3.8",
"use-deep-compare-effect": "1.8.1",
"uuid": "9.0.0",
"web-vitals": "3.0.4"
diff --git a/ui/dashboard/src/components/ErrorMessage/index.tsx b/ui/dashboard/src/components/ErrorMessage/index.tsx
index b432bd8ee..42aa1dcfb 100644
--- a/ui/dashboard/src/components/ErrorMessage/index.tsx
+++ b/ui/dashboard/src/components/ErrorMessage/index.tsx
@@ -1,8 +1,10 @@
+import { isValidElement } from "react";
+
const getErrorMessage = (error: any, fallbackMessage: string) => {
if (!error) {
return fallbackMessage;
}
- if (typeof error === "string") {
+ if (isValidElement(error)) {
return error;
}
if (error.message) {
diff --git a/ui/dashboard/src/components/Modal/ErrorModal.js b/ui/dashboard/src/components/Modal/ErrorModal.js
deleted file mode 100644
index c4366f035..000000000
--- a/ui/dashboard/src/components/Modal/ErrorModal.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import ErrorMessage from "../ErrorMessage";
-import Modal from "./index";
-import { ErrorIcon } from "../../constants/icons";
-
-const ErrorModal = ({ error, title }) => {
- return (
- }
- message={
-
-
-
- }
- title={title}
- />
- );
-};
-
-export default ErrorModal;
diff --git a/ui/dashboard/src/components/Modal/ErrorModal.tsx b/ui/dashboard/src/components/Modal/ErrorModal.tsx
new file mode 100644
index 000000000..c5beb5e6f
--- /dev/null
+++ b/ui/dashboard/src/components/Modal/ErrorModal.tsx
@@ -0,0 +1,17 @@
+import ErrorMessage from "../ErrorMessage";
+import Modal from "./index";
+import { ErrorIcon } from "../../constants/icons";
+
+const ErrorModal = ({ error, title }) => (
+ }
+ message={
+
+
+
+ }
+ title={title}
+ />
+);
+
+export default ErrorModal;
diff --git a/ui/dashboard/src/components/Modal/index.js b/ui/dashboard/src/components/Modal/index.js
deleted file mode 100644
index c6c33e9e1..000000000
--- a/ui/dashboard/src/components/Modal/index.js
+++ /dev/null
@@ -1,83 +0,0 @@
-import { CloseIcon } from "../../constants/icons";
-import { Dialog, Transition } from "@headlessui/react";
-import { Fragment, useState } from "react";
-
-const Modal = ({ icon, message, title }) => {
- const [open, setOpen] = useState(true);
-
- return (
-
-
-
-
-
-
-
- {/* This element is to trick the browser into centering the modal contents. */}
-
-
-
-
-
-
- setOpen(false)}
- >
- Close
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default Modal;
diff --git a/ui/dashboard/src/components/Modal/index.tsx b/ui/dashboard/src/components/Modal/index.tsx
new file mode 100644
index 000000000..f770b1cd0
--- /dev/null
+++ b/ui/dashboard/src/components/Modal/index.tsx
@@ -0,0 +1,86 @@
+import { CloseIcon } from "../../constants/icons";
+import { Dialog, Transition } from "@headlessui/react";
+import { Fragment, useState } from "react";
+import { ModalThemeWrapper } from "../../hooks/useTheme";
+
+const Modal = ({ icon, message, title }) => {
+ const [open, setOpen] = useState(true);
+
+ return (
+
+
+
+
+
+
+
+
+ {/* This element is to trick the browser into centering the modal contents. */}
+
+
+
+
+
+
+ setOpen(false)}
+ >
+ Close
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Modal;
diff --git a/ui/dashboard/src/components/VersionErrorMismatch/index.tsx b/ui/dashboard/src/components/VersionErrorMismatch/index.tsx
new file mode 100644
index 000000000..e9bb7ab4e
--- /dev/null
+++ b/ui/dashboard/src/components/VersionErrorMismatch/index.tsx
@@ -0,0 +1,35 @@
+import semver from "semver";
+
+const VersionErrorMismatch = ({ cliVersion, uiVersion }) => {
+ const uiOlder = semver.lt(uiVersion, cliVersion);
+ return (
+
+
+ {!uiOlder && (
+ <>Steampipe Dashboard UI version is newer than the CLI version.>
+ )}
+ {uiOlder && (
+ <>Steampipe Dashboard UI version is older than the CLI version.>
+ )}
+
+
+ UI:
+ {uiVersion}
+
+
+ CLI:
+ {cliVersion}
+
+
+ {!uiOlder && (
+ <>Please stop and restart your Steampipe dashboard process.>
+ )}
+ {uiOlder && (
+ <>Please hard refresh this page, or close and re-open your browser.>
+ )}
+
+
+ );
+};
+
+export default VersionErrorMismatch;
diff --git a/ui/dashboard/src/hooks/useDashboard.tsx b/ui/dashboard/src/hooks/useDashboard.tsx
index 6e4aecd8d..374688384 100644
--- a/ui/dashboard/src/hooks/useDashboard.tsx
+++ b/ui/dashboard/src/hooks/useDashboard.tsx
@@ -14,6 +14,7 @@ import sortBy from "lodash/sortBy";
import useDashboardWebSocket, { SocketActions } from "./useDashboardWebSocket";
import useDashboardWebSocketEventHandler from "./useDashboardWebSocketEventHandler";
import usePrevious from "./usePrevious";
+import VersionErrorMismatch from "../components/VersionErrorMismatch";
import {
AvailableDashboard,
AvailableDashboardsDictionary,
@@ -190,14 +191,36 @@ const wrapDefinitionInArtificialDashboard = (
};
function reducer(state, action) {
+ if (state.ignore_events) {
+ return state;
+ }
+
switch (action.type) {
case DashboardActions.DASHBOARD_METADATA:
+ const cliVersionRaw = get(action.metadata, "cli.version");
+ const uiVersionRaw = process.env.REACT_APP_VERSION;
+ const hasVersionsSet = !!cliVersionRaw && !!uiVersionRaw;
+ const cliVersion = !!cliVersionRaw
+ ? cliVersionRaw.startsWith("v")
+ ? cliVersionRaw.substring(1)
+ : cliVersionRaw
+ : null;
+ const uiVersion = !!uiVersionRaw
+ ? uiVersionRaw.startsWith("v")
+ ? uiVersionRaw.substring(1)
+ : uiVersionRaw
+ : null;
+ const mismatchedVersions = hasVersionsSet && cliVersion !== uiVersion;
return {
...state,
metadata: {
mod: {},
...action.metadata,
},
+ error: mismatchedVersions ? (
+
+ ) : null,
+ ignore_events: mismatchedVersions,
};
case DashboardActions.AVAILABLE_DASHBOARDS:
const { dashboards, dashboardsMap } = buildDashboards(
@@ -483,6 +506,7 @@ const buildSelectedDashboardInputsFromSearchParams = (searchParams) => {
const getInitialState = (searchParams, defaults: any = {}) => {
return {
+ ignore_events: false,
availableDashboardsLoaded: false,
metadata: null,
dashboards: [],
diff --git a/ui/dashboard/src/hooks/useTheme.tsx b/ui/dashboard/src/hooks/useTheme.tsx
index e42d75940..70ae250fc 100644
--- a/ui/dashboard/src/hooks/useTheme.tsx
+++ b/ui/dashboard/src/hooks/useTheme.tsx
@@ -108,6 +108,18 @@ const ThemeWrapper = ({ children }) => {
);
};
+const ModalThemeWrapper = ({ children }) => {
+ const { setWrapperRef, theme } = useTheme();
+ return (
+
+ {children}
+
+ );
+};
+
const useTheme = () => {
const context = useContext(ThemeContext);
if (context === undefined) {
@@ -118,6 +130,7 @@ const useTheme = () => {
export {
FullHeightThemeWrapper,
+ ModalThemeWrapper,
Themes,
ThemeNames,
ThemeProvider,
diff --git a/ui/dashboard/src/types/index.ts b/ui/dashboard/src/types/index.ts
index 659b70589..4323dccc8 100644
--- a/ui/dashboard/src/types/index.ts
+++ b/ui/dashboard/src/types/index.ts
@@ -3,6 +3,7 @@ import { Ref } from "react";
import { Theme } from "../hooks/useTheme";
export interface IDashboardContext {
+ ignore_events: boolean;
metadata: DashboardMetadata | null;
availableDashboardsLoaded: boolean;
@@ -200,6 +201,10 @@ interface InstalledModsDashboardMetadata {
[key: string]: ModDashboardMetadata;
}
+interface CliDashboardMetadata {
+ version: string;
+}
+
export interface CloudDashboardActorMetadata {
id: string;
handle: string;
@@ -225,6 +230,7 @@ interface CloudDashboardMetadata {
export interface DashboardMetadata {
mod: ModDashboardMetadata;
installed_mods?: InstalledModsDashboardMetadata;
+ cli?: CliDashboardMetadata;
cloud?: CloudDashboardMetadata;
telemetry: "info" | "none";
}
diff --git a/ui/dashboard/src/utils/storybook.tsx b/ui/dashboard/src/utils/storybook.tsx
index 462c1c035..6bcce098d 100644
--- a/ui/dashboard/src/utils/storybook.tsx
+++ b/ui/dashboard/src/utils/storybook.tsx
@@ -49,6 +49,7 @@ export const PanelStoryDecorator = ({
return (