@dugongjs/cli
Version:
134 lines (133 loc) • 7.62 kB
JavaScript
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"))));
}