Skip to content

Commit

Permalink
feat(DashboardNode): add node & config button
Browse files Browse the repository at this point in the history
  • Loading branch information
zettca authored and plagoa committed Dec 20, 2023
1 parent aadac65 commit 787bf3f
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 110 deletions.
165 changes: 58 additions & 107 deletions app/src/pages/Flow/Nodes/Dashboard.tsx
@@ -1,25 +1,16 @@
import { useState } from "react";
import { css } from "@emotion/css";
import { useMemo, useState } from "react";
import {
HvDashboard,
HvDashboardProps,
HvFlowNode,
HvDashboardNode,
HvFlowNodeFC,
HvFlowNodeInput,
HvFlowNodeTypeMeta,
useFlowContext,
} from "@hitachivantara/uikit-react-lab";
import {
HvButton,
HvDialog,
HvDialogActions,
HvDialogContent,
HvDialogTitle,
HvEmptyState,
HvSection,
HvTypography,
theme,
} from "@hitachivantara/uikit-react-core";
import { Info } from "@hitachivantara/uikit-react-icons";

import {
DASHBOARDS_STORAGE_KEY,
Expand All @@ -36,28 +27,12 @@ type PreviewProps = {
};

const PreviewRenderer = ({ label, node }: PreviewProps) => (
<div
className={css({
display: "flex",
flexDirection: "column",
flexWrap: "wrap",
width: "100%",
padding: theme.space.xs,
border: `1px solid ${theme.colors.atmo4}`,
borderRadius: theme.radii.round,
backgroundColor: theme.colors.atmo1,
})}
<HvSection
title={<HvTypography variant="title4">{label}</HvTypography>}
classes={{ content: "mt-0" }}
>
<HvTypography
variant="title4"
className={css({ marginBottom: theme.space.xs })}
>
{label}
</HvTypography>
<HvTypography className={css({ color: theme.colors.secondary_60 })}>
{node.data.title}
</HvTypography>
</div>
<HvTypography className="text-secondary_60">{node.data.title}</HvTypography>
</HvSection>
);

const nodeInputs: HvFlowNodeInput[] = [
Expand All @@ -75,31 +50,32 @@ export const Dashboard: HvFlowNodeFC = (props) => {

const [open, setOpen] = useState(false);
const [config, setConfig] = useState<DashboardSpecs>();
const [content, setContent] = useState<PreviewProps[]>();

const handleOpenConfig = () => {
// Get from local storage
const value = localStorage.getItem(DASHBOARDS_STORAGE_KEY);
const specs: DashboardsStorage = value ? JSON.parse(value) : undefined;
const newConfig = specs?.[id];
const content = useMemo(() => {
if (!config) return undefined;

const ct = newConfig?.items?.map<PreviewProps>((node) => {
return config.items.map<PreviewProps>((node) => {
const nodeType = node.type!;
const label = nodeType && nodeTypes?.[nodeType].meta?.label;

return { id: node.id, type: nodeType, label, node };
});
}, [config, nodeTypes]);

const handleOpenConfig = () => {
// Get from local storage
const value = localStorage.getItem(DASHBOARDS_STORAGE_KEY);
const specs: DashboardsStorage = value ? JSON.parse(value) : undefined;
const newConfig = specs?.[id];

// Open
setOpen(true);
setConfig(newConfig);
setContent(ct);
};

const handleClose = () => {
setOpen(false);
setConfig(undefined);
setContent(undefined);
};

const handleApply = () => {
Expand All @@ -113,73 +89,48 @@ export const Dashboard: HvFlowNodeFC = (props) => {
handleClose();
};

const handleLayoutChange: HvDashboardProps["onLayoutChange"] = (ly) => {
setConfig((conf) => ({ ...conf!, layout: ly }));
};

return (
<>
<HvFlowNode description="Dashboard" inputs={nodeInputs} {...props}>
<div
className={css({
display: "flex",
justifyContent: "center",
padding: theme.spacing("xs", "xs", "sm", "xs"),
gap: theme.space.xs,
})}
>
<HvButton onClick={handleOpenConfig}>Configure</HvButton>
<HvButton
variant="primarySubtle"
component="a"
href={`./?dashboard=${id}`}
target="_blank"
>
Preview
</HvButton>
<HvDashboardNode
description="Dashboard"
inputs={nodeInputs}
open={open}
layout={config?.layout}
labels={{
title: "Dashboard",
description: "Dashboard",
emptyMessage: "No visualizations connected to the dashboard.",
dialogTitle: "Configure dashboard",
dialogSubtitle:
"Please configure the layout of your dashboard as needed.",
dialogApply: "Apply",
dialogCancel: "Cancel",
}}
onClose={handleClose}
onApply={handleApply}
onCancel={handleClose}
dashboardProps={{
cols: config?.cols,
onLayoutChange: (ly) => {
setConfig((conf) => ({ ...conf!, layout: ly }));
},
}}
previewItems={content?.map((item) => (
<div key={item.id} className="flex">
<PreviewRenderer {...item} />
</div>
</HvFlowNode>
<HvDialog maxWidth="lg" fullWidth open={open} onClose={handleClose}>
<HvDialogTitle variant="info">Configure Dashboard</HvDialogTitle>
<HvDialogContent indentContent>
<HvTypography>
Please configure the layout of your dashboard as needed.
</HvTypography>
{config?.layout && config.layout.length > 0 ? (
<HvDashboard
layout={config.layout}
compactType="vertical"
rowHeight={80}
margin={[16, 16]}
containerPadding={[0, 16]}
onLayoutChange={handleLayoutChange}
>
{content?.map((item) => (
<div key={item.id} className={css({ display: "flex" })}>
<PreviewRenderer {...item} />
</div>
))}
</HvDashboard>
) : (
<HvEmptyState
className={css({
padding: theme.spacing("sm", 0, 0, 0),
})}
icon={<Info />}
message="No visualizations connected to the dashboard."
/>
)}
</HvDialogContent>
<HvDialogActions>
<HvButton variant="primary" onClick={handleApply}>
Apply
</HvButton>
<HvButton variant="secondarySubtle" onClick={handleClose}>
Cancel
</HvButton>
</HvDialogActions>
</HvDialog>
</>
))}
{...props}
>
<HvButton onClick={handleOpenConfig}>Configure</HvButton>
<HvButton
variant="primarySubtle"
component="a"
href={`./?dashboard=${id}`}
target="_blank"
>
Preview
</HvButton>
</HvDashboardNode>
);
};

Expand Down
1 change: 1 addition & 0 deletions packages/lab/src/Flow/index.ts
Expand Up @@ -8,4 +8,5 @@ export * from "./Node";
export type { HvFlowClasses } from "./DroppableFlow";
export { flowClasses } from "./DroppableFlow";
export * from "./types";
export * from "./nodes";
export * from "./hooks";
123 changes: 123 additions & 0 deletions packages/lab/src/Flow/nodes/DashboardNode.tsx
@@ -0,0 +1,123 @@
import {
ExtractNames,
HvButton,
HvDialog,
HvDialogActions,
HvDialogContent,
HvDialogProps,
HvDialogTitle,
HvEmptyState,
createClasses,
theme,
useLabels,
} from "@hitachivantara/uikit-react-core";
import { Info } from "@hitachivantara/uikit-react-icons";

import { HvDashboard, HvDashboardProps } from "../../Dashboard";
import { HvFlowNode, HvFlowNodeProps, HvFlowNodeClasses } from "../Node";

const { staticClasses, useClasses } = createClasses("HvDashboardNode", {
actions: {
display: "flex",
justifyContent: "space-around",
padding: theme.space.xs,
},
empty: {
padding: theme.spacing("sm", 0, 0, 0),
},
});

export { staticClasses as hvDashboardNodeClasses };

const DEFAULT_LABELS = {
title: "Dashboard",
description: "Dashboard",
emptyMessage: "No visualizations connected to the dashboard.",
dialogTitle: "Configure dashboard",
dialogSubtitle: "Please configure the layout of your dashboard as needed.",
dialogApply: "Apply",
dialogCancel: "Cancel",
};

export interface HvDashboardNodeClasses
extends ExtractNames<typeof useClasses>,
HvFlowNodeClasses {}

export interface HvDashboardNodeProps
extends HvFlowNodeProps,
Pick<HvDialogProps, "open" | "onClose">,
Pick<HvDashboardProps, "layout"> {
classes?: HvDashboardNodeClasses;
labels?: typeof DEFAULT_LABELS;
previewItems?: React.ReactNode;
onApply?: () => void;
onCancel?: () => void;

dashboardProps?: Omit<HvDashboardProps, "children">;
dialogProps?: HvDialogProps;
}

export const HvDashboardNode = (props: HvDashboardNodeProps) => {
const {
id,
open,
layout,
labels: labelsProp,
classes: classesProp,
previewItems,
children,
dialogProps,
dashboardProps,
onApply,
onCancel,
onClose,
...others
} = props;
const labels = useLabels(DEFAULT_LABELS, labelsProp);
const { classes } = useClasses(classesProp);

return (
<HvFlowNode id={id} classes={classes as any} {...others}>
<div className={classes.actions}>{children}</div>
<HvDialog
open={open}
maxWidth="lg"
fullWidth
onClose={onClose}
{...dialogProps}
>
<HvDialogTitle variant="info">{labels?.dialogTitle}</HvDialogTitle>
<HvDialogContent indentContent>
{labels?.dialogSubtitle}
{layout && layout?.length > 0 ? (
<HvDashboard
cols={12}
layout={layout}
compactType="vertical"
rowHeight={80}
margin={[16, 16]}
containerPadding={[0, 16]}
{...dashboardProps}
>
{previewItems}
</HvDashboard>
) : (
<HvEmptyState
className={classes.empty}
icon={<Info role="none" />}
message={labels?.emptyMessage}
/>
)}
</HvDialogContent>
<HvDialogActions>
<HvButton variant="primary" onClick={onApply}>
{labels?.dialogApply}
</HvButton>
<HvButton variant="secondarySubtle" onClick={onCancel}>
{labels?.dialogCancel}
</HvButton>
</HvDialogActions>
</HvDialog>
</HvFlowNode>
);
};
1 change: 1 addition & 0 deletions packages/lab/src/Flow/nodes/index.ts
@@ -0,0 +1 @@
export * from "./DashboardNode";

0 comments on commit 787bf3f

Please sign in to comment.