Skip to content

Commit

Permalink
Rework dashboard UI internals to avoid infinite render loops (#625)
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelBurgess authored Dec 12, 2024
1 parent ce164cc commit 40b718a
Show file tree
Hide file tree
Showing 79 changed files with 1,496 additions and 1,734 deletions.
52 changes: 28 additions & 24 deletions internal/dashboardserver/payload.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,12 @@ func addBenchmarkChildren(benchmark *resources.Benchmark, recordTrunk bool, trun
trunks[t.FullName] = append(trunks[t.FullName], childTrunk)
}
availableBenchmark := ModAvailableBenchmark{
Title: t.GetTitle(),
FullName: t.FullName,
ShortName: t.ShortName,
Tags: t.Tags,
Children: addBenchmarkChildren(t, recordTrunk, childTrunk, trunks),
Title: t.GetTitle(),
FullName: t.FullName,
ShortName: t.ShortName,
BenchmarkType: "control",
Tags: t.Tags,
Children: addBenchmarkChildren(t, recordTrunk, childTrunk, trunks),
}
children = append(children, availableBenchmark)
}
Expand All @@ -191,11 +192,12 @@ func addDetectionBenchmarkChildren(benchmark *resources.DetectionBenchmark, reco
trunks[t.FullName] = append(trunks[t.FullName], childTrunk)
}
availableBenchmark := ModAvailableBenchmark{
Title: t.GetTitle(),
FullName: t.FullName,
ShortName: t.ShortName,
Tags: t.Tags,
Children: addDetectionBenchmarkChildren(t, recordTrunk, childTrunk, trunks),
Title: t.GetTitle(),
FullName: t.FullName,
ShortName: t.ShortName,
BenchmarkType: "detection",
Tags: t.Tags,
Children: addDetectionBenchmarkChildren(t, recordTrunk, childTrunk, trunks),
}
children = append(children, availableBenchmark)
}
Expand Down Expand Up @@ -253,13 +255,14 @@ func buildAvailableDashboardsPayload(workspaceResources *resources.PowerpipeModR
}

availableBenchmark := ModAvailableBenchmark{
Title: benchmark.GetTitle(),
FullName: benchmark.FullName,
ShortName: benchmark.ShortName,
Tags: benchmark.Tags,
IsTopLevel: isTopLevel,
Children: addBenchmarkChildren(benchmark, isTopLevel, trunk, benchmarkTrunks),
ModFullName: mod.GetFullName(),
Title: benchmark.GetTitle(),
FullName: benchmark.FullName,
ShortName: benchmark.ShortName,
BenchmarkType: "control",
Tags: benchmark.Tags,
IsTopLevel: isTopLevel,
Children: addBenchmarkChildren(benchmark, isTopLevel, trunk, benchmarkTrunks),
ModFullName: mod.GetFullName(),
}

payload.Benchmarks[benchmark.FullName] = availableBenchmark
Expand Down Expand Up @@ -294,13 +297,14 @@ func buildAvailableDashboardsPayload(workspaceResources *resources.PowerpipeModR
}

availableDetectionBenchmark := ModAvailableBenchmark{
Title: detectionBenchmark.GetTitle(),
FullName: detectionBenchmark.FullName,
ShortName: detectionBenchmark.ShortName,
Tags: detectionBenchmark.Tags,
IsTopLevel: isTopLevel,
Children: addDetectionBenchmarkChildren(detectionBenchmark, isTopLevel, trunk, detectionBenchmarkTrunks),
ModFullName: mod.GetFullName(),
Title: detectionBenchmark.GetTitle(),
FullName: detectionBenchmark.FullName,
ShortName: detectionBenchmark.ShortName,
BenchmarkType: "detection",
Tags: detectionBenchmark.Tags,
IsTopLevel: isTopLevel,
Children: addDetectionBenchmarkChildren(detectionBenchmark, isTopLevel, trunk, detectionBenchmarkTrunks),
ModFullName: mod.GetFullName(),
}

payload.Benchmarks[detectionBenchmark.FullName] = availableDetectionBenchmark
Expand Down
17 changes: 9 additions & 8 deletions internal/dashboardserver/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,15 @@ type ModAvailableDashboard struct {
}

type ModAvailableBenchmark struct {
Title string `json:"title,omitempty"`
FullName string `json:"full_name"`
ShortName string `json:"short_name"`
Tags map[string]string `json:"tags"`
IsTopLevel bool `json:"is_top_level"`
Children []ModAvailableBenchmark `json:"children,omitempty"`
Trunks [][]string `json:"trunks"`
ModFullName string `json:"mod_full_name"`
Title string `json:"title,omitempty"`
FullName string `json:"full_name"`
ShortName string `json:"short_name"`
BenchmarkType string `json:"benchmark_type"`
Tags map[string]string `json:"tags"`
IsTopLevel bool `json:"is_top_level"`
Children []ModAvailableBenchmark `json:"children,omitempty"`
Trunks [][]string `json:"trunks"`
ModFullName string `json:"mod_full_name"`
}

type AvailableDashboardsPayload struct {
Expand Down
24 changes: 7 additions & 17 deletions ui/dashboard/src/components/CallToActions/index.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,18 @@
import { DashboardCliMode } from "@powerpipe/types";
import { getComponent } from "../dashboards";

interface CallToActionsProps {
cliMode: DashboardCliMode;
}

const items = (cliMode: DashboardCliMode) => [
const items = [
{
title: "Find a Dashboard",
description: `${cliMode === "powerpipe" ? "Powerpipe" : "Steampipe"} Hub has hundreds of open source dashboards to get you started.`,
href:
cliMode === "powerpipe"
? "https://hub.powerpipe.io"
: "https://hub.steampipe.io/mods",
description:
"Powerpipe Hub has hundreds of open source dashboards to get you started.",
href: "https://hub.powerpipe.io",
withReferrer: true,
},
{
title: "Build a Dashboard",
description:
"It's easy to create your own dashboard as code! Start with this tutorial.",
href:
cliMode === "powerpipe"
? "https://powerpipe.io/docs/build/writing-dashboards"
: "https://steampipe.io/docs/mods/writing-dashboards",
href: "https://powerpipe.io/docs/build/writing-dashboards",
withReferrer: true,
},
{
Expand All @@ -34,11 +24,11 @@ const items = (cliMode: DashboardCliMode) => [
},
];

const CallToActions = ({ cliMode }: CallToActionsProps) => {
const CallToActions = () => {
const ExternalLink = getComponent("external_link");
return (
<ul className="mt-4 md:mt-0 space-y-6">
{items(cliMode).map((item, itemIdx) => (
{items.map((item, itemIdx) => (
<li key={itemIdx} className="flow-root">
<div className="p-3 flex items-center space-x-4 rounded-md hover:bg-dashboard-panel focus-within:ring-2 focus-within:ring-blue-500">
<ExternalLink
Expand Down
6 changes: 2 additions & 4 deletions ui/dashboard/src/components/CodeBlock/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import sql from "react-syntax-highlighter/dist/esm/languages/prism/sql";
import { classNames } from "@powerpipe/utils/styles";
import { PrismLight as SyntaxHighlighter } from "react-syntax-highlighter";
import { ThemeNames } from "@powerpipe/hooks/useTheme";
import { useDashboard } from "@powerpipe/hooks/useDashboard";
import { useDashboardTheme } from "@powerpipe/hooks/useDashboardTheme";
import { useMemo, useState } from "react";
import {
vs,
Expand All @@ -30,9 +30,7 @@ const CodeBlock = ({
style = {},
}: CodeBlockProps) => {
const [showCopyIcon, setShowCopyIcon] = useState(false);
const {
themeContext: { theme },
} = useDashboard();
const { theme } = useDashboardTheme();

const styles = useMemo(() => {
const commonStyles = {
Expand Down
86 changes: 3 additions & 83 deletions ui/dashboard/src/components/DashboardControlsSummary/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import {
CheckDisplayGroup,
Filter,
} from "@powerpipe/components/dashboards/grouping/common";
import { classNames } from "@powerpipe/utils/styles";
import { Filter } from "@powerpipe/components/dashboards/grouping/common";
import { Noop } from "@powerpipe/types/func";
import { ReactNode } from "react";
import { validateFilter } from "@powerpipe/components/dashboards/grouping/FilterEditor";

type DashboardControlsSummaryProps = {
searchPathPrefix: string[];
filterConfig: Filter;
groupingConfig: CheckDisplayGroup[];
onClose: Noop;
};

Expand Down Expand Up @@ -54,48 +49,6 @@ const DashboardFilterButton = ({
</button>
);

const DashboardSearchPathPrefixControlButton = ({
searchPathPrefix,
toggleControls,
}) => {
// <div className="flex items-center space-x-3 shrink-0">
// <Icon className="h-5 w-5 shrink-0" icon="list" />
// <div className="space-x-0.5 truncate">
// {modifiedSearchPath.length > 0 &&
// modifiedSearchPath
// .map<ReactNode>((item, i) => (
// <span key={`${item}-${i}`} className="font-medium">
// {item}
// </span>
// ))
// .reduce((prev, curr, idx) => [
// prev,
// <span key={idx} className="text-foreground-lighter">
// ,
// </span>,
// curr,
// ])}
// {modifiedSearchPath.length === 0 && (
// <span className="text-foreground-lighter">
// No search path prefix set
// </span>
// )}
// </div>
// <Icon
// className="h-5 w-5 cursor-pointer shrink-0"
// icon="edit_square"
// onClick={() => setShowEditor(true)}
// title="Edit search path prefix"
// />
// </div>;

return (
<DashboardFilterButton onClick={toggleControls}>
Search Path
</DashboardFilterButton>
);
};

const DashboardFilterControlButton = ({ filterConfig, toggleControls }) => {
const filterCount = filterConfig?.expressions?.length
? filterConfig.expressions.filter(validateFilter).length
Expand Down Expand Up @@ -129,31 +82,7 @@ const DashboardFilterControlButton = ({ filterConfig, toggleControls }) => {
);
};

const DashboardGroupingControlButton = ({ groupingConfig, toggleControls }) => {
// <div className="flex items-center space-x-3 shrink-0">
// <Icon className="h-5 w-5" icon="workspaces" />
// {groupingConfig
// .map<ReactNode>((item) => (
// <CheckGroupingTitleLabel
// key={`${item.type}${!!item.value ? `-${item.value}` : ""}`}
// item={item}
// />
// ))
// .reduce((prev, curr, idx) => [
// prev,
// <Icon key={idx} className="h-4 w-4" icon="arrow-long-right" />,
// curr,
// ])}
// {!showEditor && (
// <Icon
// className="h-5 w-5 cursor-pointer shrink-0"
// icon="edit_square"
// onClick={() => setShowEditor(true)}
// title="Edit grouping"
// />
// )}
// </div>

const DashboardGroupingControlButton = ({ toggleControls }) => {
return (
<DashboardFilterButton onClick={toggleControls}>
Grouping
Expand All @@ -162,26 +91,17 @@ const DashboardGroupingControlButton = ({ groupingConfig, toggleControls }) => {
};

const DashboardControlsSummary = ({
searchPathPrefix,
filterConfig,
groupingConfig,
onClose,
}: DashboardControlsSummaryProps) => {
return (
<>
<div className="grow flex items-center justify-end space-x-4">
{/*<DashboardSearchPathPrefixControlButton*/}
{/* searchPathPrefix={searchPathPrefix}*/}
{/* toggleControls={toggleControls}*/}
{/*/>*/}
<DashboardFilterControlButton
filterConfig={filterConfig}
toggleControls={onClose}
/>
<DashboardGroupingControlButton
groupingConfig={groupingConfig}
toggleControls={onClose}
/>
<DashboardGroupingControlButton toggleControls={onClose} />
</div>
</>
);
Expand Down
9 changes: 4 additions & 5 deletions ui/dashboard/src/components/DashboardHeader/PowerpipeLogo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@ import { ReactComponent as LogoWordmark } from "./logos/powerpipe-logo-wordmark.
// @ts-ignore
import { ReactComponent as LogoWordmarkDarkmode } from "./logos/powerpipe-logo-wordmark-darkmode.svg";
import { ThemeNames } from "@powerpipe/hooks/useTheme";
import { useDashboard } from "@powerpipe/hooks/useDashboard";
import { useDashboardSearchPath } from "@powerpipe/hooks/useDashboardSearchPath";
import { useDashboardTheme } from "@powerpipe/hooks/useDashboardTheme";

const PowerpipeLogo = () => {
const {
themeContext: { theme },
searchPathPrefix,
} = useDashboard();
const { searchPathPrefix } = useDashboardSearchPath();
const { theme } = useDashboardTheme();
const ExternalLink = getComponent("external_link");

return (
Expand Down
Loading

0 comments on commit 40b718a

Please sign in to comment.