UNPKG

@dugongjs/cli

Version:

134 lines (133 loc) 7.62 kB
import { Box, measureElement, Spacer, Text, useApp, useInput } from "ink"; import React from "react"; import { getAggregateQueryAdapter } from "../adapters/resolver.js"; import formatAggregate from "../utils/format-aggregate.js"; import { useStdoutDimensions } from "./hooks/use-stdout-dimensions.js"; import { AggregateDiffPane } from "./panes/aggregate-diff-pane.js"; import { AggregateIdSelectPane } from "./panes/aggregate-id-select-pane.js"; import { AggregateTypeSelectPane } from "./panes/aggregate-type-select-pane.js"; import { AggregateViewPane } from "./panes/aggregate-view-pane.js"; import { DomainEventSelectPane } from "./panes/domain-event-select-pane.js"; import { DomainEventViewPane } from "./panes/domain-event-view-pane.js"; const PaneIndex = { AGGREGATE_TYPE: 0, AGGREGATE_ID: 1, DOMAIN_EVENT: 2 }; export function MainView(props) { const { preselectedType, preselectedId } = props; const app = useApp(); const [_, rows] = useStdoutDimensions(); const [activePaneIndex, setActivePaneIndex] = React.useState(PaneIndex.AGGREGATE_TYPE); const totalPanes = 3; useInput((_, key) => { if (key.tab && !key.shift) { setActivePaneIndex((prev) => ((prev + 1) % totalPanes)); } else if (key.shift && key.tab) { setActivePaneIndex((prev) => ((prev - 1 + totalPanes) % totalPanes)); } }); useInput((_, key) => { if (key.escape) { app.exit(); } }); const [types, setTypes] = React.useState([]); const [selectedType, setSelectedType] = React.useState(preselectedType ?? null); const [ids, setIds] = React.useState([]); const [selectedId, setSelectedId] = React.useState(preselectedId ?? null); const [aggregate, setAggregate] = React.useState(null); const [previousAggregate, setPreviousAggregate] = React.useState(null); const [domainEvents, setDomainEvents] = React.useState([]); const [selectedDomainEventIndex, setSelectedDomainEventIndex] = React.useState(null); const [adapter, setAdapter] = React.useState(null); const containerRef = React.useRef(null); const [containerSize, setContainerSize] = React.useState({ width: 0, height: 0 }); React.useEffect(() => { const { adapter, close } = getAggregateQueryAdapter(); setAdapter(adapter); return () => { close?.(); }; }, []); React.useEffect(() => { if (adapter) { adapter .getAggregateTypes() .then(setTypes) .catch((error) => console.error("Error retrieving aggregate types:", error.message)); } }, [adapter]); React.useEffect(() => { if (adapter && selectedType) { adapter .getAggregateIds(null, selectedType) .then(setIds) .catch((error) => console.error("Error retrieving aggregate IDs:", error.message)); setActivePaneIndex(PaneIndex.AGGREGATE_ID); } }, [adapter, selectedType]); React.useEffect(() => { if (adapter && selectedType && selectedId) { adapter .getDomainEventsForAggregate(null, selectedType, selectedId) .then((domainEvents) => { setDomainEvents(domainEvents); setSelectedDomainEventIndex(domainEvents.length - 1); }) .catch((error) => console.error("Error retrieving domain events:", error.message)); setActivePaneIndex(PaneIndex.DOMAIN_EVENT); } }, [adapter, selectedId]); React.useEffect(() => { if (adapter && selectedType && selectedId) { adapter .getAggregate(null, selectedType, selectedId, domainEvents[selectedDomainEventIndex ?? 0]?.sequenceNumber) .then((aggregate) => setAggregate(aggregate)) .catch((error) => console.error("Error retrieving aggregate:", error.message)); if (selectedDomainEventIndex && selectedDomainEventIndex > 0) { adapter .getAggregate(null, selectedType, selectedId, domainEvents[selectedDomainEventIndex - 1]?.sequenceNumber) .then((previousAggregate) => setPreviousAggregate(previousAggregate)) .catch((error) => console.error("Error retrieving previous aggregate:", error.message)); } } }, [adapter, selectedType, selectedId, selectedDomainEventIndex]); React.useEffect(() => { if (containerRef.current) { const size = measureElement(containerRef.current); setContainerSize(size); } }, [rows]); return (React.createElement(Box, { ref: containerRef, width: "100%", height: "100%", flexDirection: "column" }, React.createElement(Box, { width: "100%", height: containerSize.height - 2, flexDirection: "row", flexWrap: "nowrap" }, React.createElement(Box, { width: "25%", height: "100%", flexDirection: "column" }, React.createElement(Box, { width: "100%", height: "25%" }, React.createElement(AggregateTypeSelectPane, { types: types, selectedType: selectedType, setSelectedType: setSelectedType, isFocused: activePaneIndex === PaneIndex.AGGREGATE_TYPE })), React.createElement(Box, { width: "100%", height: "75%" }, React.createElement(AggregateIdSelectPane, { ids: ids, selectedType: selectedType, selectedId: selectedId, setSelectedId: setSelectedId, isFocused: activePaneIndex === PaneIndex.AGGREGATE_ID }))), React.createElement(Box, { width: "40%", height: "100%", flexDirection: "column" }, React.createElement(Box, { width: "100%", height: "75%" }, React.createElement(AggregateViewPane, { aggregateType: selectedType, aggregateId: selectedId, aggregate: formatAggregate(aggregate), isDeleted: aggregate?.isDeletedInternal ?? false })), React.createElement(Box, { width: "100%", height: "25%" }, React.createElement(AggregateDiffPane, { current: formatAggregate({ ...aggregate, isDeleted: aggregate?.isDeletedInternal ?? false }), previous: formatAggregate({ ...previousAggregate, isDeleted: previousAggregate?.isDeletedInternal ?? false }) }))), React.createElement(Box, { width: "35%", height: "100%", flexDirection: "column" }, React.createElement(Box, { width: "100%", height: "25%" }, React.createElement(DomainEventSelectPane, { domainEvents: domainEvents, selectedDomainEventIndex: selectedDomainEventIndex, setSelectedDomainEventIndex: setSelectedDomainEventIndex, isFocused: activePaneIndex === PaneIndex.DOMAIN_EVENT })), React.createElement(Box, { width: "100%", height: "75%" }, React.createElement(DomainEventViewPane, { domainEvent: domainEvents[selectedDomainEventIndex ?? 0], maximumSequenceNumber: Math.max(...domainEvents.map((domainEvent) => domainEvent.sequenceNumber ?? 0)) })))), React.createElement(Box, { width: "100%", height: 2, marginTop: 1, paddingX: 2, flexDirection: "row" }, React.createElement(Text, { color: "gray" }, "\u21B9 / \u21E7 + \u21B9 : switch pane \u2022 Esc : exit"), React.createElement(Spacer, null), React.createElement(Text, { color: "blueBright" }, "dugongjs studio")))); }