291 lines
6.8 KiB
JavaScript
291 lines
6.8 KiB
JavaScript
const React = require("react");
|
|
const { Box, Text } = require("ink");
|
|
const { useState, useEffect } = React;
|
|
const useAppState = require("../hooks/useAppState.js");
|
|
const useNavigation = require("../hooks/useNavigation.js");
|
|
const { useServiceContext } = require("../providers/ServiceProvider.jsx");
|
|
|
|
/**
|
|
* StatusBar Component
|
|
* Displays global status information at the top of the application
|
|
* Shows connection status, operation progress, and current screen
|
|
* Requirements: 8.1, 8.2, 8.3
|
|
*/
|
|
const StatusBar = () => {
|
|
const { operationState, configuration } = useAppState();
|
|
const { currentScreen } = useNavigation();
|
|
const {
|
|
testConnection,
|
|
isInitialized,
|
|
error: serviceError,
|
|
} = useServiceContext();
|
|
const [connectionStatus, setConnectionStatus] = useState({
|
|
status: "disconnected",
|
|
lastChecked: null,
|
|
error: null,
|
|
});
|
|
|
|
// Test connection status periodically using ShopifyService
|
|
useEffect(() => {
|
|
const performConnectionTest = async () => {
|
|
try {
|
|
// Only test connection if services are initialized and we have configuration
|
|
if (!isInitialized) {
|
|
setConnectionStatus({
|
|
status: "initializing",
|
|
lastChecked: new Date(),
|
|
error: "Services initializing...",
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (serviceError) {
|
|
setConnectionStatus({
|
|
status: "error",
|
|
lastChecked: new Date(),
|
|
error: serviceError,
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (!configuration.shopDomain || !configuration.accessToken) {
|
|
setConnectionStatus({
|
|
status: "not_configured",
|
|
lastChecked: new Date(),
|
|
error: "Missing configuration",
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Set connecting status
|
|
setConnectionStatus((prev) => ({
|
|
...prev,
|
|
status: "connecting",
|
|
}));
|
|
|
|
// Use ShopifyService to test connection
|
|
const isConnected = await testConnection();
|
|
|
|
setConnectionStatus({
|
|
status: isConnected ? "connected" : "disconnected",
|
|
lastChecked: new Date(),
|
|
error: isConnected ? null : "Connection failed",
|
|
});
|
|
} catch (error) {
|
|
setConnectionStatus({
|
|
status: "error",
|
|
lastChecked: new Date(),
|
|
error: error.message,
|
|
});
|
|
}
|
|
};
|
|
|
|
// Test connection immediately if services are ready
|
|
if (isInitialized) {
|
|
performConnectionTest();
|
|
}
|
|
|
|
// Test connection every 30 seconds
|
|
const interval = setInterval(() => {
|
|
if (isInitialized) {
|
|
performConnectionTest();
|
|
}
|
|
}, 30000);
|
|
|
|
return () => clearInterval(interval);
|
|
}, [
|
|
configuration.shopDomain,
|
|
configuration.accessToken,
|
|
isInitialized,
|
|
serviceError,
|
|
testConnection,
|
|
]);
|
|
|
|
// Get connection display info
|
|
const getConnectionInfo = () => {
|
|
switch (connectionStatus.status) {
|
|
case "connected":
|
|
return {
|
|
text: "Connected",
|
|
color: "green",
|
|
indicator: "●",
|
|
};
|
|
case "connecting":
|
|
return {
|
|
text: "Connecting...",
|
|
color: "yellow",
|
|
indicator: "◐",
|
|
};
|
|
case "initializing":
|
|
return {
|
|
text: "Initializing...",
|
|
color: "yellow",
|
|
indicator: "◑",
|
|
};
|
|
case "not_configured":
|
|
return {
|
|
text: "Not Configured",
|
|
color: "gray",
|
|
indicator: "○",
|
|
};
|
|
case "error":
|
|
return {
|
|
text: "Connection Error",
|
|
color: "red",
|
|
indicator: "●",
|
|
};
|
|
case "disconnected":
|
|
default:
|
|
return {
|
|
text: "Disconnected",
|
|
color: "red",
|
|
indicator: "○",
|
|
};
|
|
}
|
|
};
|
|
|
|
// Get operation status info
|
|
const getOperationInfo = () => {
|
|
if (!operationState) {
|
|
return null;
|
|
}
|
|
|
|
const { status, progress, type, currentProduct } = operationState;
|
|
|
|
switch (status) {
|
|
case "running":
|
|
return {
|
|
text: `${type === "rollback" ? "Rollback" : "Update"}: ${
|
|
progress || 0
|
|
}%`,
|
|
color: "blue",
|
|
indicator: "▶",
|
|
details: currentProduct ? `Processing: ${currentProduct}` : null,
|
|
};
|
|
case "completed":
|
|
return {
|
|
text: `${type === "rollback" ? "Rollback" : "Update"} Complete`,
|
|
color: "green",
|
|
indicator: "✓",
|
|
};
|
|
case "error":
|
|
return {
|
|
text: `${type === "rollback" ? "Rollback" : "Update"} Failed`,
|
|
color: "red",
|
|
indicator: "✗",
|
|
};
|
|
case "paused":
|
|
return {
|
|
text: `${type === "rollback" ? "Rollback" : "Update"} Paused`,
|
|
color: "yellow",
|
|
indicator: "⏸",
|
|
};
|
|
default:
|
|
return {
|
|
text: "Ready",
|
|
color: "gray",
|
|
indicator: "○",
|
|
};
|
|
}
|
|
};
|
|
|
|
// Get current screen name for display
|
|
const getScreenName = () => {
|
|
const screenNames = {
|
|
"main-menu": "Main Menu",
|
|
configuration: "Configuration",
|
|
operation: "Operation",
|
|
scheduling: "Scheduling",
|
|
logs: "Logs",
|
|
"tag-analysis": "Tag Analysis",
|
|
};
|
|
return screenNames[currentScreen] || "Unknown";
|
|
};
|
|
|
|
// Get system status indicator
|
|
const getSystemStatus = () => {
|
|
if (operationState?.status === "error") {
|
|
return { color: "red", text: "ERROR" };
|
|
}
|
|
if (operationState?.status === "running") {
|
|
return { color: "blue", text: "ACTIVE" };
|
|
}
|
|
if (connectionStatus.status === "error") {
|
|
return { color: "red", text: "CONN_ERR" };
|
|
}
|
|
if (connectionStatus.status === "connected") {
|
|
return { color: "green", text: "READY" };
|
|
}
|
|
return { color: "gray", text: "IDLE" };
|
|
};
|
|
|
|
const connectionInfo = getConnectionInfo();
|
|
const operationInfo = getOperationInfo();
|
|
const systemStatus = getSystemStatus();
|
|
|
|
return React.createElement(
|
|
Box,
|
|
{
|
|
borderStyle: "single",
|
|
paddingX: 1,
|
|
justifyContent: "space-between",
|
|
height: 3,
|
|
},
|
|
// Left side: Connection and screen info
|
|
React.createElement(
|
|
Box,
|
|
{ flexDirection: "column" },
|
|
React.createElement(
|
|
Box,
|
|
null,
|
|
React.createElement(
|
|
Text,
|
|
{ color: connectionInfo.color },
|
|
`${connectionInfo.indicator} `
|
|
),
|
|
React.createElement(Text, null, connectionInfo.text),
|
|
React.createElement(Text, { color: "gray" }, " | "),
|
|
React.createElement(Text, null, `Screen: ${getScreenName()}`)
|
|
),
|
|
connectionStatus.error &&
|
|
React.createElement(
|
|
Text,
|
|
{ color: "red", dimColor: true },
|
|
`Error: ${connectionStatus.error.substring(0, 40)}${
|
|
connectionStatus.error.length > 40 ? "..." : ""
|
|
}`
|
|
)
|
|
),
|
|
// Right side: Operation status and system status
|
|
React.createElement(
|
|
Box,
|
|
{ flexDirection: "column", alignItems: "flex-end" },
|
|
React.createElement(
|
|
Box,
|
|
null,
|
|
operationInfo &&
|
|
React.createElement(
|
|
Text,
|
|
{ color: operationInfo.color },
|
|
`${operationInfo.indicator} ${operationInfo.text}`
|
|
),
|
|
operationInfo && React.createElement(Text, { color: "gray" }, " | "),
|
|
React.createElement(
|
|
Text,
|
|
{ color: systemStatus.color, bold: true },
|
|
systemStatus.text
|
|
)
|
|
),
|
|
operationInfo?.details &&
|
|
React.createElement(
|
|
Text,
|
|
{ color: "gray", dimColor: true },
|
|
operationInfo.details.substring(0, 30) +
|
|
(operationInfo.details.length > 30 ? "..." : "")
|
|
)
|
|
)
|
|
);
|
|
};
|
|
|
|
module.exports = StatusBar;
|