Update widgets and added settings
This commit is contained in:
@@ -9,7 +9,6 @@ export default function AlertLevel({id, isEditable, isDelete, DeleteWidget}) {
|
|||||||
const [isSubmit, setIsSubmit] = useState(false);
|
const [isSubmit, setIsSubmit] = useState(false);
|
||||||
|
|
||||||
const onSubmit = (data) => {
|
const onSubmit = (data) => {
|
||||||
console.log("data: ", data);
|
|
||||||
setIsSubmit(true);
|
setIsSubmit(true);
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,11 @@ import { Box, Flex, Spinner, Text } from '@chakra-ui/react';
|
|||||||
import Plot from 'react-plotly.js';
|
import Plot from 'react-plotly.js';
|
||||||
import VdapApi from '../../hooks/useVdapApi.js'; // Adjust path as needed
|
import VdapApi from '../../hooks/useVdapApi.js'; // Adjust path as needed
|
||||||
|
|
||||||
export default function VaaActivity7Day() {
|
export default function VaaActivity7Day({ settings }) {
|
||||||
|
console.log("3. Chart received settings:", settings);
|
||||||
|
// Plotly expects 'linear' for normal axes
|
||||||
|
const plotYAxisType = settings?.yAxisScale === 'symlog' ? 'symlog' : 'linear';
|
||||||
|
|
||||||
// Clean, single-line data fetching
|
// Clean, single-line data fetching
|
||||||
const { data: apiData, isLoading, error } = VdapApi('/api/v2/comm_coor_vaa');
|
const { data: apiData, isLoading, error } = VdapApi('/api/v2/comm_coor_vaa');
|
||||||
|
|
||||||
@@ -59,7 +63,7 @@ export default function VaaActivity7Day() {
|
|||||||
paper_bgcolor: 'transparent', // Let Chakra UI background show through
|
paper_bgcolor: 'transparent', // Let Chakra UI background show through
|
||||||
plot_bgcolor: 'transparent',
|
plot_bgcolor: 'transparent',
|
||||||
font: { color: '#d1d5db' }, // gray.300
|
font: { color: '#d1d5db' }, // gray.300
|
||||||
margin: { t: 20, r: 20, l: 20, b: 20 },
|
margin: { t: 40, r: 20, l: 20, b: 20 },
|
||||||
// title: {
|
// title: {
|
||||||
// text: '7 Day Consolidated Flight Levels',
|
// text: '7 Day Consolidated Flight Levels',
|
||||||
// font: { size: 16, color: 'white' },
|
// font: { size: 16, color: 'white' },
|
||||||
@@ -81,6 +85,7 @@ export default function VaaActivity7Day() {
|
|||||||
text: 'Flight Level',
|
text: 'Flight Level',
|
||||||
font: { color: 'white', size: 12 }
|
font: { color: 'white', size: 12 }
|
||||||
},
|
},
|
||||||
|
type: plotYAxisType,
|
||||||
gridcolor: '#4b5563',
|
gridcolor: '#4b5563',
|
||||||
zerolinecolor: '#ffffff',
|
zerolinecolor: '#ffffff',
|
||||||
automargin: true,
|
automargin: true,
|
||||||
@@ -105,7 +110,7 @@ export default function VaaActivity7Day() {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
}, [apiData]);
|
}, [apiData, plotYAxisType]);
|
||||||
|
|
||||||
if (isLoading) return (
|
if (isLoading) return (
|
||||||
<Flex w="100%" h="100%" bg="gray.800" borderRadius="md" align="center" justify="center">
|
<Flex w="100%" h="100%" bg="gray.800" borderRadius="md" align="center" justify="center">
|
||||||
@@ -128,6 +133,7 @@ export default function VaaActivity7Day() {
|
|||||||
return (
|
return (
|
||||||
<Box height="100%" width="100%" bg="gray.800" borderRadius="md" p={2} overflow="hidden">
|
<Box height="100%" width="100%" bg="gray.800" borderRadius="md" p={2} overflow="hidden">
|
||||||
<Plot
|
<Plot
|
||||||
|
key={plotYAxisType}
|
||||||
data={plotTraces}
|
data={plotTraces}
|
||||||
layout={layout}
|
layout={layout}
|
||||||
useResizeHandler={true} // Essential for dashboard grid resizing!
|
useResizeHandler={true} // Essential for dashboard grid resizing!
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { Box, Text, Switch } from "@chakra-ui/react";
|
||||||
|
import { useDashboardStore } from "../../../store/useDashboardStore.jsx";
|
||||||
|
|
||||||
|
export default function VaaActivitySettings({ widgetId, currentSettings }) {
|
||||||
|
const updateSettings = useDashboardStore(state => state.updateWidgetSettings);
|
||||||
|
|
||||||
|
// 1. Convert the saved string into a boolean for the toggle UI
|
||||||
|
const isSymlog = currentSettings?.yAxisScale === 'symlog';
|
||||||
|
|
||||||
|
const handleToggle = (details) => {
|
||||||
|
// 2. Chakra v3 passes { checked: boolean } in the details object.
|
||||||
|
// Convert it back to the string Plotly expects.
|
||||||
|
console.log("1. Toggle Clicked! Raw details from Chakra:", details);
|
||||||
|
|
||||||
|
const newScale = details.checked ? 'symlog' : 'normal';
|
||||||
|
|
||||||
|
updateSettings(widgetId, { yAxisScale: newScale });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Text fontWeight="bold" mb={3} fontSize="sm">Y-Axis Settings</Text>
|
||||||
|
|
||||||
|
<Switch.Root
|
||||||
|
checked={isSymlog}
|
||||||
|
onCheckedChange={handleToggle}
|
||||||
|
colorPalette="blue"
|
||||||
|
>
|
||||||
|
<Switch.HiddenInput />
|
||||||
|
<Switch.Control>
|
||||||
|
<Switch.Thumb />
|
||||||
|
</Switch.Control>
|
||||||
|
<Switch.Label>Use Symlog Scale</Switch.Label>
|
||||||
|
</Switch.Root>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -13,6 +13,15 @@ export const WIDGET_REGISTRY = {
|
|||||||
category: "Aviation",
|
category: "Aviation",
|
||||||
description: "Displays 7-day flight level timelines across multiple volcanoes.",
|
description: "Displays 7-day flight level timelines across multiple volcanoes.",
|
||||||
component: lazy(() => import('../components/widgets/VaaActivity7Day')),
|
component: lazy(() => import('../components/widgets/VaaActivity7Day')),
|
||||||
|
|
||||||
|
// The specific settings UI for this widget
|
||||||
|
settingsComponent: lazy(() => import('../components/widgets/settings/VaaActivitySettings')),
|
||||||
|
|
||||||
|
// The baseline data every new VAA widget starts with
|
||||||
|
defaultSettings: {
|
||||||
|
yAxisScale: 'normal' // Options: 'normal' | 'symlog'
|
||||||
|
},
|
||||||
|
|
||||||
allowedSizes: {
|
allowedSizes: {
|
||||||
xlarge: { w: 12, h: 12 },
|
xlarge: { w: 12, h: 12 },
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Box, Text, Flex, IconButton, Spinner } from "@chakra-ui/react";
|
import { Box, Text, Flex, IconButton, Spinner, Popover } from "@chakra-ui/react";
|
||||||
import { X } from "lucide-react";
|
import { X, MoreVertical } from "lucide-react";
|
||||||
import { Responsive, WidthProvider } from "react-grid-layout";
|
import { Responsive, WidthProvider } from "react-grid-layout";
|
||||||
import { useDashboardStore } from "@/store/useDashboardStore.jsx";
|
import { useDashboardStore } from "@/store/useDashboardStore.jsx";
|
||||||
import { Suspense, useEffect, useRef } from 'react';
|
import { Suspense, useEffect, useRef } from 'react';
|
||||||
@@ -62,30 +62,60 @@ export default function MyDashboard() {
|
|||||||
if (registryEntry && registryEntry.component) {
|
if (registryEntry && registryEntry.component) {
|
||||||
const Component = registryEntry.component;
|
const Component = registryEntry.component;
|
||||||
|
|
||||||
|
// 1. Check if this widget type has a settings component registered
|
||||||
|
const SettingsUI = registryEntry.settingsComponent;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// The "Frame" that holds both the Title and the Chart
|
// The "Frame" that holds both the Title and the Chart
|
||||||
<Flex direction="column" height="100%" width="100%" bg="gray.800">
|
<Flex direction="column" height="100%" width="100%" bg="gray.800">
|
||||||
|
|
||||||
{/* 1. THE TITLE BAR (Dynamically pulled from registry!) */}
|
{/* THE TITLE BAR */}
|
||||||
<Flex
|
<Flex
|
||||||
justify="space-between"
|
justify="space-between"
|
||||||
align="center"
|
align="center"
|
||||||
px={3}
|
px={3}
|
||||||
py={2}
|
py={2}
|
||||||
// borderBottom="1px solid"
|
|
||||||
// borderColor="gray.700"
|
|
||||||
>
|
>
|
||||||
<Text color="gray.100" fontWeight="semibold" fontSize="md" isTruncated>
|
<Text color="gray.100" fontWeight="semibold" fontSize="md" isTruncated>
|
||||||
{registryEntry.name}
|
{registryEntry.name}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{/* (Optional) This is exactly where the ellipsis/settings icon will go later! */}
|
{/* THE SETTINGS ELLIPSIS */}
|
||||||
|
{SettingsUI ? (
|
||||||
|
<Popover.Root positioning={{ placement: "bottom-end" }}>
|
||||||
|
<Popover.Trigger asChild>
|
||||||
|
<IconButton
|
||||||
|
size="xs"
|
||||||
|
variant="ghost"
|
||||||
|
color="gray.400"
|
||||||
|
_hover={{ color: "white", bg: "gray.700" }}
|
||||||
|
aria-label="Widget Settings"
|
||||||
|
>
|
||||||
|
<MoreVertical size={16} />
|
||||||
|
</IconButton>
|
||||||
|
</Popover.Trigger>
|
||||||
|
|
||||||
|
{/* NEW: The Positioner lifts the content out of the Flexbox flow */}
|
||||||
|
<Popover.Positioner zIndex={10}>
|
||||||
|
<Popover.Content bg="gray.50" p={4} boxShadow="xl" borderRadius="md">
|
||||||
|
<Suspense fallback={<Spinner size="sm" />}>
|
||||||
|
<SettingsUI
|
||||||
|
widgetId={widget.id}
|
||||||
|
currentSettings={widget.settings || {}}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
|
</Popover.Content>
|
||||||
|
</Popover.Positioner>
|
||||||
|
</Popover.Root>
|
||||||
|
) : (
|
||||||
<Box w="20px" h="20px" />
|
<Box w="20px" h="20px" />
|
||||||
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
{/* 2. THE CHART CANVAS */}
|
{/* THE CHART CANVAS */}
|
||||||
<Box flex="1" overflow="hidden" position="relative" p={1}>
|
<Box flex="1" overflow="hidden" position="relative" p={1}>
|
||||||
<Component />
|
{/* Pass the settings object into the actual chart component */}
|
||||||
|
<Component settings={widget.settings || {}} />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -43,6 +43,17 @@ export const useDashboardStore = create((set, get) => ({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateWidgetSettings: (id, newSettings) => set((state) => {
|
||||||
|
console.log("2. Zustand updating widget:", id, "with:", newSettings);
|
||||||
|
return {
|
||||||
|
widgets: state.widgets.map(widget =>
|
||||||
|
widget.id === id
|
||||||
|
? { ...widget, settings: { ...widget.settings, ...newSettings } }
|
||||||
|
: widget
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
|
||||||
addWidget: (widgetId, sizeKey) => {
|
addWidget: (widgetId, sizeKey) => {
|
||||||
const registryEntry = WIDGET_REGISTRY[widgetId];
|
const registryEntry = WIDGET_REGISTRY[widgetId];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user