Skip to content

Commit

Permalink
feat: time viewer for config changes
Browse files Browse the repository at this point in the history
Fixes #93
  • Loading branch information
mainawycliffe committed Oct 29, 2024
1 parent 171bb82 commit e33099d
Show file tree
Hide file tree
Showing 7 changed files with 1,206 additions and 68 deletions.
1,071 changes: 1,015 additions & 56 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
"react-use-size": "^3.0.3",
"react-windowed-select": "^5.2.0",
"reactflow": "^11.11.3",
"reaviz": "^15.18.5",
"recharts": "2.1.12",
"strip-ansi": "^7.1.0",
"tailwindcss": "^3.4.1",
Expand Down
125 changes: 125 additions & 0 deletions src/components/Configs/Changes/ConfigChangesGraph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { ConfigChange } from "@flanksource-ui/api/types/configs";
import { Age } from "@flanksource-ui/ui/Age";
import { ChangeIcon } from "@flanksource-ui/ui/Icons/ChangeIcon";
import dayjs from "dayjs";
import { useMemo } from "react";
import {
ChartShallowDataShape,
ChartTooltip,
LinearXAxis,
LinearXAxisTickLabel,
LinearXAxisTickLine,
LinearXAxisTickSeries,
LinearYAxis,
LinearYAxisTickLabel,
LinearYAxisTickSeries,
ScatterPlot,
ScatterPoint,
ScatterSeries
} from "reaviz";
import ConfigsTypeIcon from "../ConfigsTypeIcon";

type ConfigChangesGraphProps = {
changes: ConfigChange[];
};

export default function ConfigChangesGraph({
changes
}: ConfigChangesGraphProps) {
const data: ChartShallowDataShape[] = useMemo(() => {
// group changes by config_id, then map to a scatter plot point
return changes.map((change) => {
return {
key: dayjs(change.first_observed).toDate(),
data: change.config?.name!,
metadata: change
};
});
}, [changes]);

return (
<div className="h-full w-full">
<ScatterPlot
data={data}
yAxis={
<LinearYAxis
type="category"
tickSeries={
<LinearYAxisTickSeries
label={<LinearYAxisTickLabel padding={3} fontSize={12} />}
/>
}
/>
}
xAxis={
<LinearXAxis
type="category"
tickSeries={
<LinearXAxisTickSeries
line={<LinearXAxisTickLine position="center" />}
label={<LinearXAxisTickLabel padding={3} />}
/>
}
/>
}
series={
<ScatterSeries
point={
<ScatterPoint
tooltip={
<ChartTooltip
followCursor={true}
content={(data: any) => {
const count = (data.metadata as ConfigChange).count;
const firstObserved = (data.metadata as ConfigChange)
.first_observed;
const summary = (data.metadata as ConfigChange).summary;

return (
<div className="flex flex-col gap-1 rounded-lg bg-gray-100 p-2 text-black shadow-sm">
<ConfigsTypeIcon
config={(data.metadata as ConfigChange).config}
>
{(data.metadata as ConfigChange).config?.name}
</ConfigsTypeIcon>
<div className="flex flex-col gap-1">
<div className="flex flex-row items-center justify-center gap-2 text-xs">
<span className="flex flex-row items-center gap-1 font-semibold">
<ChangeIcon change={data.metadata} />
{(data.metadata as ConfigChange).change_type}
</span>
<span className="font-semibold">
<Age
from={
(data.metadata as ConfigChange)
.first_observed
}
/>
{(count || 1) > 1 && (
<span className="inline-block pl-1 text-gray-500">
(x{count} over <Age from={firstObserved} />)
</span>
)}
</span>
</div>
<p>{summary}</p>
</div>
</div>
);
}}
/>
}
className={"bg-gray-500"}
size={20}
symbol={(data) => {
const change = data.metadata;
return <ChangeIcon change={change} />;
}}
/>
}
/>
}
/>
</div>
);
}
34 changes: 34 additions & 0 deletions src/components/Configs/Changes/ConfigChangesViewToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Switch } from "@flanksource-ui/ui/FormControls/Switch";
import { useAtom } from "jotai";
import { atomWithStorage } from "jotai/utils";

export type GraphType = "Table" | "Graph";
export const configChangesViewToggle = atomWithStorage<GraphType>(
"configChangesViewToggleState",
"Table",
undefined,
{
getOnInit: true
}
);

export function useConfigChangesViewToggleState() {
const [hideDeletedConfigs] = useAtom(configChangesViewToggle);
return hideDeletedConfigs;
}

export default function ConfigChangesViewToggle() {
const [toggleValue, setToggleValue] = useAtom(configChangesViewToggle);

return (
<div className="ml-auto flex flex-row items-center gap-2 px-2">
<Switch
options={["Table", "Graph"]}
onChange={(v) => {
setToggleValue(v as GraphType);
}}
value={toggleValue}
/>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { FilterBadge } from "../../ConfigChangesFilters/ConfigChangesFilters";
import { ConfigRelatedChangesToggles } from "../../ConfigChangesFilters/ConfigRelatedChangesToggles";
import { ConfigTagsDropdown } from "../../ConfigChangesFilters/ConfigTagsDropdown";
import ConfigTypesTristateDropdown from "../../ConfigChangesFilters/ConfigTypesTristateDropdown";
import ConfigChangesViewToggle from "../../ConfigChangesViewToggle";
import { ConfigChangesToggledDeletedItems } from "./ConfigChangesToggledDeletedItems";

type ConfigChangeFiltersProps = {
Expand All @@ -22,19 +23,27 @@ export function ConfigRelatedChangesFilters({
const arbitraryFilters = useConfigChangesArbitraryFilters();

return (
<div className="flex flex-col gap-2">
<div className="flex w-full flex-col gap-2">
<FormikFilterForm
paramsToReset={paramsToReset}
filterFields={["configTypes", "changeType", "severity", "tags"]}
>
<div className={clsx("flex flex-wrap items-center gap-2", className)}>
<div
className={clsx(
"flex w-full flex-wrap items-center gap-2",
className
)}
>
<ConfigTypesTristateDropdown />
<ChangesTypesDropdown />
<ConfigChangeSeverity />
<ConfigTagsDropdown />
<ConfigRelatedChangesToggles />
<ConfigChangesDateRangeFilter paramsToReset={paramsToReset} />
<ConfigChangesToggledDeletedItems />
<div className="ml-auto flex flex-row gap-2">
<ConfigChangesViewToggle />
</div>
</div>
</FormikFilterForm>
<div className="flex flex-wrap gap-2">
Expand Down
1 change: 1 addition & 0 deletions src/pages/config/ConfigChangesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export function ConfigChangesPage() {
) : (
<>
<ConfigChangeFilters paramsToReset={["page"]} />

<ConfigChangeTable
data={changes}
isLoading={isLoading || isRefetching}
Expand Down
29 changes: 19 additions & 10 deletions src/pages/config/details/ConfigDetailsChangesPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { useGetConfigChangesByIDQuery } from "@flanksource-ui/api/query-hooks/useConfigChangesHooks";
import ConfigChangesGraph from "@flanksource-ui/components/Configs/Changes/ConfigChangesGraph";
import { useConfigChangesViewToggleState } from "@flanksource-ui/components/Configs/Changes/ConfigChangesViewToggle";
import { ConfigChangeTable } from "@flanksource-ui/components/Configs/Changes/ConfigChangeTable";
import { ConfigRelatedChangesFilters } from "@flanksource-ui/components/Configs/Changes/ConfigsRelatedChanges/FilterBar/ConfigRelatedChangesFilters";
import { ConfigDetailsTabs } from "@flanksource-ui/components/Configs/ConfigDetailsTabs";
Expand All @@ -16,10 +18,13 @@ export function ConfigDetailsChangesPage() {
const page = params.get("page") ?? "1";
const pageSize = params.get("pageSize") ?? "200";

const { data, isLoading, error, refetch } = useGetConfigChangesByIDQuery({
keepPreviousData: true,
enabled: !!id
});
const { data, isLoading, error, refetch, isRefetching } =
useGetConfigChangesByIDQuery({
keepPreviousData: true,
enabled: !!id
});

const view = useConfigChangesViewToggleState();

const changes = (data?.changes ?? []).map((changes) => ({
...changes,
Expand Down Expand Up @@ -77,12 +82,16 @@ export function ConfigDetailsChangesPage() {
<div className="flex w-full flex-1 flex-col items-start gap-2 overflow-y-auto">
<ConfigRelatedChangesFilters paramsToReset={["page"]} />
<div className="flex w-full flex-1 flex-col overflow-y-auto">
<ConfigChangeTable
data={changes}
isLoading={isLoading}
numberOfPages={totalChangesPages}
totalRecords={totalChanges}
/>
{view === "Graph" ? (
<ConfigChangesGraph changes={changes} />
) : (
<ConfigChangeTable
data={changes}
isLoading={isLoading || isRefetching}
totalRecords={totalChanges}
numberOfPages={totalChangesPages}
/>
)}
</div>
</div>
</div>
Expand Down

0 comments on commit e33099d

Please sign in to comment.