Remove edge gateway components and templates associated with outdated workflows.

This commit is contained in:
Jeppe Bundgaard
2026-04-20 14:51:53 +02:00
parent 5d30690dfd
commit 1a784bbbfd
79 changed files with 7228 additions and 6241 deletions
+349 -207
View File
@@ -635,9 +635,74 @@ function mergeEdgeGatewayFixtureRecord(baseGateway, overrides = {}) {
bindings: Array.isArray(overrides.bindings) ? overrides.bindings : baseGateway.bindings,
recent_commands: Array.isArray(overrides.recent_commands) ? overrides.recent_commands : baseGateway.recent_commands,
audit_logs: Array.isArray(overrides.audit_logs) ? overrides.audit_logs : baseGateway.audit_logs,
operations: Array.isArray(overrides.operations) ? overrides.operations : baseGateway.operations || [],
};
}
function createFixtureOperation(type, request = {}, overrides = {}) {
const startedAt = overrides.started_at || null;
const completedAt = overrides.completed_at || null;
return {
id: overrides.id || Date.now(),
type,
status: overrides.status || "PENDING",
request,
summary: overrides.summary || {
label:
overrides.status === "COMPLETED"
? "Completed"
: overrides.status === "FAILED"
? "Failed"
: "Queued",
progress: overrides.status === "COMPLETED" ? 100 : overrides.status === "FAILED" ? 100 : 0,
retryable: overrides.status !== "FAILED",
},
result: overrides.result || {},
error_code: overrides.error_code || null,
error_message: overrides.error_message || null,
requested_at: overrides.requested_at || toSqlDateTime(),
started_at: startedAt,
completed_at: completedAt,
created_at: overrides.created_at || toSqlDateTime(),
updated_at: overrides.updated_at || completedAt || startedAt || toSqlDateTime(),
events: Array.isArray(overrides.events) ? overrides.events : [],
};
}
function buildEdgeGatewayOperationSummary(operations = []) {
return operations.reduce(
(summary, operation, index) => {
const status = String(operation.status || "PENDING");
if (status === "PENDING") summary.pending += 1;
if (status === "IN_PROGRESS") summary.in_progress += 1;
if (status === "COMPLETED") {
summary.completed += 1;
summary.latest_completed_at = summary.latest_completed_at || operation.completed_at || null;
}
if (status === "FAILED") {
summary.failed += 1;
summary.latest_failed_at = summary.latest_failed_at || operation.completed_at || null;
}
if (index === 0) {
summary.latest_type = operation.type || null;
summary.latest_status = operation.status || null;
}
return summary;
},
{
total: operations.length,
pending: 0,
in_progress: 0,
completed: 0,
failed: 0,
latest_completed_at: null,
latest_failed_at: null,
latest_type: null,
latest_status: null,
}
);
}
function buildEdgeGatewayRuntimeFixture(gateway) {
const relayHealth = (gateway.bindings || []).map((binding) => {
const fallbackMode = binding.fallback_mode || "PREFER_LOCAL";
@@ -662,6 +727,27 @@ function buildEdgeGatewayRuntimeFixture(gateway) {
});
const cloudRelays = relayHealth.filter((relay) => relay.execution_path === "cloud");
const operations = Array.isArray(gateway.operations) ? gateway.operations : [];
const activeOperation = operations.find((operation) => ["PENDING", "IN_PROGRESS"].includes(String(operation.status))) || null;
const versionDrift =
gateway.installed_version && gateway.target_version && gateway.installed_version !== gateway.target_version;
const credentialFreshnessState = gateway.metadata?.credentials_rotated_at ? "FRESH" : "UNKNOWN";
const diagnostics = [];
if (gateway.status === "OFFLINE") {
diagnostics.push({
code: "EDGE_GATEWAY_OFFLINE",
message: "Gateway heartbeat has expired and the gateway is offline.",
recommended_action: "restart_agent",
});
}
if (versionDrift) {
diagnostics.push({
code: "EDGE_GATEWAY_VERSION_DRIFT",
message: "Installed gateway version differs from the target version.",
recommended_action: "queue_update",
});
}
return {
...gateway,
@@ -697,6 +783,25 @@ function buildEdgeGatewayRuntimeFixture(gateway) {
relay_health: gateway.relay_health || relayHealth,
last_successful_command_at: gateway.last_successful_command_at || gateway.last_heartbeat_at,
last_successful_discovery_at: gateway.last_successful_discovery_at || gateway.last_heartbeat_at,
active_operation: gateway.active_operation || activeOperation,
recent_operations_summary: gateway.recent_operations_summary || buildEdgeGatewayOperationSummary(operations),
version_drift:
gateway.version_drift || {
installed_version: gateway.installed_version || null,
target_version: gateway.target_version || null,
release_channel: gateway.release_channel || "stable",
is_drifted: Boolean(versionDrift),
status: versionDrift ? "UPDATE_AVAILABLE" : "IN_SYNC",
},
credential_freshness:
gateway.credential_freshness || {
rotated_at: gateway.metadata?.credentials_rotated_at || null,
age_days: gateway.metadata?.credentials_rotated_at ? 1 : null,
state: credentialFreshnessState,
},
diagnostics: gateway.diagnostics || diagnostics,
error_state:
gateway.error_state || (diagnostics[0] ? { ...diagnostics[0] } : activeOperation?.error_code ? { code: activeOperation.error_code, message: activeOperation.error_message } : null),
};
}
@@ -779,6 +884,18 @@ function createEdgeGatewayFixture(options = {}) {
},
],
recent_commands: [],
operations: [
createFixtureOperation("DISCOVERY", {}, {
id: 8801,
status: "COMPLETED",
started_at: "2026-04-08 08:14:20",
completed_at: "2026-04-08 08:14:38",
events: [
{ id: 1, level: "INFO", code: "OPERATION_STARTED", message: "Gateway started processing the operation", created_at: "2026-04-08 08:14:20" },
{ id: 2, level: "INFO", code: "OPERATION_COMPLETED", message: "Operation completed successfully", created_at: "2026-04-08 08:14:38" },
],
}),
],
audit_logs: [{ id: 501, created_at: "2026-04-08 08:16:00", action: "GATEWAY_CLAIMED", actor_type: "USER" }],
},
{
@@ -813,6 +930,7 @@ function createEdgeGatewayFixture(options = {}) {
inventory: [],
bindings: [],
recent_commands: [],
operations: [],
audit_logs: [{ id: 502, created_at: "2026-04-07 21:05:00", action: "HEARTBEAT_TIMEOUT", actor_type: "SYSTEM" }],
},
].map((gateway) =>
@@ -844,10 +962,27 @@ function settleEdgeGatewayWork(edgeGatewayFixture, gatewayId) {
if (!gateway.inventory.some((device) => device.device_id === pendingDiscovery.device.device_id)) {
gateway.inventory = [...gateway.inventory, pendingDiscovery.device];
}
gateway.recent_commands = (gateway.recent_commands || []).map((job) =>
Number(job.id) === Number(pendingDiscovery.jobId)
? { ...job, status: "COMPLETED", completed_at: gateway.last_successful_discovery_at }
: job
gateway.operations = (gateway.operations || []).map((operation) =>
Number(operation.id) === Number(pendingDiscovery.operationId)
? {
...operation,
status: "COMPLETED",
completed_at: gateway.last_successful_discovery_at,
updated_at: gateway.last_successful_discovery_at,
summary: { ...(operation.summary || {}), label: "Completed", progress: 100, retryable: true },
result: { inventory: cloneJson(gateway.inventory) },
events: [
...(operation.events || []),
{
id: edgeGatewayFixture.nextOperationEventId++,
level: "INFO",
code: "OPERATION_COMPLETED",
message: "Operation completed successfully",
created_at: gateway.last_successful_discovery_at,
},
],
}
: operation
);
delete edgeGatewayFixture.pendingDiscoveryByGatewayId[gatewayId];
}
@@ -862,65 +997,13 @@ function cloneJson(value) {
return JSON.parse(JSON.stringify(value));
}
function edgeGatewayOperationsFor(edgeGatewayFixture, gatewayId) {
if (!Array.isArray(edgeGatewayFixture.operationsByGatewayId[gatewayId])) {
edgeGatewayFixture.operationsByGatewayId[gatewayId] = [];
}
return edgeGatewayFixture.operationsByGatewayId[gatewayId];
}
function edgeGatewaySessionsFor(edgeGatewayFixture, gatewayId) {
if (!Array.isArray(edgeGatewayFixture.shellSessionsByGatewayId[gatewayId])) {
edgeGatewayFixture.shellSessionsByGatewayId[gatewayId] = [];
}
return edgeGatewayFixture.shellSessionsByGatewayId[gatewayId];
}
function publicEdgeGatewayOperation(operation) {
if (!operation) {
return null;
}
const { events, progress_step, ...publicFields } = operation;
return {
...publicFields,
request: cloneJson(publicFields.request || {}),
result: cloneJson(publicFields.result || {}),
summary: cloneJson(publicFields.summary || {}),
latest_event: Array.isArray(events) && events.length > 0 ? cloneJson(events[events.length - 1]) : null,
};
}
function publicEdgeGatewaySession(session) {
if (!session) {
return null;
}
return {
...session,
metadata: cloneJson(session.metadata || {}),
};
}
function buildHttpEdgeGatewayGateway(edgeGatewayFixture, gateway, includeDetail = false) {
const inventory = cloneJson(gateway.inventory || []);
const bindings = cloneJson(gateway.bindings || []);
const operations = edgeGatewayOperationsFor(edgeGatewayFixture, gateway.id)
.slice()
.sort((left, right) => Number(right.id) - Number(left.id));
const activeOperation =
operations.find((operation) => ["PENDING", "RUNNING"].includes(String(operation.status || "").toUpperCase())) ||
null;
const recentShellSessions = edgeGatewaySessionsFor(edgeGatewayFixture, gateway.id)
.slice()
.sort((left, right) => Number(right.id) - Number(left.id))
.map((session) => publicEdgeGatewaySession(session));
const operations = cloneJson(gateway.operations || []);
return {
...cloneJson(gateway),
control_plane: { mode: "HTTP_POLLING" },
readiness: {
status: gateway.status,
last_heartbeat_at: gateway.last_heartbeat_at,
@@ -945,137 +1028,19 @@ function buildHttpEdgeGatewayGateway(edgeGatewayFixture, gateway, includeDetail
last_heartbeat_at: gateway.last_heartbeat_at,
system_metrics: cloneJson(gateway.metadata?.system_metrics || {}),
},
active_operation: activeOperation ? publicEdgeGatewayOperation(activeOperation) : null,
recent_operations: operations.map((operation) => publicEdgeGatewayOperation(operation)),
operations,
active_operation: cloneJson(gateway.active_operation || null),
recent_operations_summary: cloneJson(gateway.recent_operations_summary || buildEdgeGatewayOperationSummary(operations)),
version_drift: cloneJson(gateway.version_drift || null),
credential_freshness: cloneJson(gateway.credential_freshness || null),
diagnostics: cloneJson(gateway.diagnostics || []),
error_state: cloneJson(gateway.error_state || null),
inventory: includeDetail ? inventory : undefined,
bindings: includeDetail ? bindings : undefined,
recent_shell_sessions: includeDetail ? recentShellSessions : undefined,
audit_logs: includeDetail ? cloneJson(gateway.audit_logs || []) : undefined,
};
}
function addEdgeGatewayOperationEvent(edgeGatewayFixture, operation, stage, message, payload = {}, level = "INFO", counts = {}) {
const event = {
id: edgeGatewayFixture.nextOperationEventId++,
operation_id: operation.id,
gateway_id: operation.gateway_id,
stage,
level,
message,
counts,
payload,
created_at: toSqlDateTime(),
};
operation.events.push(event);
operation.summary = {
latest_stage: stage,
latest_message: message,
counts,
};
return event;
}
function advanceEdgeGatewayOperation(edgeGatewayFixture, gateway, operation) {
if (!gateway || !operation || ["COMPLETED", "FAILED"].includes(String(operation.status || "").toUpperCase())) {
return;
}
if (operation.operation_type === "DISCOVERY") {
gateway.discovery_status = "RUNNING";
if (operation.progress_step === 0) {
addEdgeGatewayOperationEvent(edgeGatewayFixture, operation, "STARTED", "Discovery started on the gateway.");
addEdgeGatewayOperationEvent(edgeGatewayFixture, operation, "PROBE", "Probing 10.1.0.0/24 for Shelly devices.");
operation.progress_step = 1;
return;
}
if (operation.progress_step === 1) {
const discoveredDevice = {
id: gateway.inventory.length + 1,
device_id: "shelly-plus-new",
local_ip: "10.1.0.33",
model: "Shelly Plus 1PM",
channel_count: 1,
online: true,
capabilities: { generation: 2 },
};
if (!gateway.inventory.some((device) => device.device_id === discoveredDevice.device_id)) {
gateway.inventory.push(discoveredDevice);
}
addEdgeGatewayOperationEvent(
edgeGatewayFixture,
operation,
"DEVICE_FOUND",
"Found shelly-plus-new during discovery.",
{ device: discoveredDevice },
"INFO",
{ devices: gateway.inventory.length }
);
operation.progress_step = 2;
return;
}
operation.status = "COMPLETED";
operation.completed_at = toSqlDateTime();
operation.result = { inventory: cloneJson(gateway.inventory) };
gateway.discovery_status = "READY";
addEdgeGatewayOperationEvent(
edgeGatewayFixture,
operation,
"COMPLETED",
`Discovery completed with ${gateway.inventory.length} device(s).`,
{},
"INFO",
{ devices: gateway.inventory.length }
);
return;
}
if (operation.operation_type === "UPDATE") {
if (operation.progress_step === 0) {
addEdgeGatewayOperationEvent(edgeGatewayFixture, operation, "STARTED", "Update started on the gateway.");
operation.progress_step = 1;
return;
}
gateway.installed_version = operation.request_json?.target_version || gateway.installed_version;
gateway.target_version = operation.request_json?.target_version || gateway.target_version;
operation.status = "COMPLETED";
operation.completed_at = toSqlDateTime();
operation.result = { installed_version: gateway.installed_version };
addEdgeGatewayOperationEvent(edgeGatewayFixture, operation, "COMPLETED", `Gateway updated to ${gateway.installed_version}.`);
return;
}
if (operation.operation_type === "UNINSTALL") {
if (operation.progress_step === 0) {
addEdgeGatewayOperationEvent(edgeGatewayFixture, operation, "STARTED", "Uninstall started on the gateway.");
operation.progress_step = 1;
return;
}
gateway.status = "OFFLINE";
operation.status = "COMPLETED";
operation.completed_at = toSqlDateTime();
operation.result = { service_name: "truckwash-edge-agent.service" };
addEdgeGatewayOperationEvent(edgeGatewayFixture, operation, "COMPLETED", "Gateway uninstall completed.");
return;
}
operation.status = "COMPLETED";
operation.completed_at = toSqlDateTime();
operation.result = {
online: true,
on: Boolean(operation.request_json?.on),
};
addEdgeGatewayOperationEvent(edgeGatewayFixture, operation, "COMPLETED", `${operation.operation_type} completed.`);
}
function processPendingEdgeGatewayClaims(edgeGatewayFixture) {
edgeGatewayFixture.pendingClaims = (edgeGatewayFixture.pendingClaims || []).filter((claim) => {
claim.pollsRemaining -= 1;
@@ -1110,6 +1075,7 @@ function processPendingEdgeGatewayClaims(edgeGatewayFixture) {
inventory: [],
bindings: [],
recent_commands: [],
operations: [],
audit_logs: [
{
id: Date.now(),
@@ -1165,6 +1131,18 @@ function createHttpEdgeGatewayFixture(options = {}) {
{ id: 2, relay_id: "M-7-LEGACY", device_id: "shelly-missing-legacy", local_ip: "10.1.0.99", channel: 1, fallback_mode: "CLOUD_ONLY" },
],
recent_commands: [],
operations: [
createFixtureOperation("DISCOVERY", {}, {
id: 8801,
status: "COMPLETED",
started_at: "2026-04-08 08:14:20",
completed_at: "2026-04-08 08:14:38",
events: [
{ id: 1, level: "INFO", code: "OPERATION_STARTED", message: "Gateway started processing the operation", created_at: "2026-04-08 08:14:20" },
{ id: 2, level: "INFO", code: "OPERATION_COMPLETED", message: "Operation completed successfully", created_at: "2026-04-08 08:14:38" },
],
}),
],
audit_logs: [{ id: 501, created_at: "2026-04-08 08:16:00", action: "GATEWAY_CLAIMED", actor_type: "USER" }],
},
{
@@ -1193,6 +1171,7 @@ function createHttpEdgeGatewayFixture(options = {}) {
inventory: [],
bindings: [],
recent_commands: [],
operations: [],
audit_logs: [{ id: 502, created_at: "2026-04-07 21:05:00", action: "HEARTBEAT_TIMEOUT", actor_type: "SYSTEM" }],
},
]
@@ -1201,15 +1180,11 @@ function createHttpEdgeGatewayFixture(options = {}) {
return {
nextGatewayId: Math.max(703, ...baseGateways.map((gateway) => Number(gateway.id) + 1)),
nextOperationId: 10001,
nextOperationEventId: 20001,
nextShellSessionId: 30001,
nextShellEventId: 40001,
nextOperationId: 9901,
nextOperationEventId: 19901,
claimPollsRemaining: Number(options.claimPollsRemaining || 2),
pendingClaims: [],
pendingDiscoveryByGatewayId: {},
operationsByGatewayId: {},
shellSessionsByGatewayId: {},
gateways: baseGateways,
};
}
@@ -2434,6 +2409,16 @@ async function handleEdgeGatewayRoute({
const findGateway = (gatewayId) =>
edgeGatewayFixture.gateways.find((entry) => Number(entry.id) === Number(gatewayId)) || null;
const gatewayResponse = (gateway, includeDetail = true) =>
gateway ? json({ data: buildHttpEdgeGatewayGateway(edgeGatewayFixture, gateway, includeDetail) }) : json({ message: "Gateway not found" }, 404);
const createOperation = (gateway, type, request = {}, overrides = {}) => {
const operation = createFixtureOperation(type, request, {
id: edgeGatewayFixture.nextOperationId++,
...overrides,
});
gateway.operations = [operation, ...(gateway.operations || [])];
return operation;
};
if (pathname.endsWith("/edge-gateways") && method === "GET") {
processPendingEdgeGatewayClaims(edgeGatewayFixture);
@@ -2464,25 +2449,174 @@ async function handleEdgeGatewayRoute({
return true;
}
if (/\/edge-gateways\/\d+\/operations$/.test(pathname) && method === "GET") {
const gatewayId = extractMatchId(/\/edge-gateways\/(\d+)\/operations$/);
const gateway = settleEdgeGatewayWork(edgeGatewayFixture, gatewayId);
await route.fulfill(json({ data: cloneJson(gateway?.operations || []) }));
return true;
}
if (/\/edge-gateways\/\d+\/operations\/\d+\/events$/.test(pathname) && method === "GET") {
const gatewayId = extractMatchId(/\/edge-gateways\/(\d+)\/operations\/\d+\/events$/);
const operationId = extractMatchId(/\/operations\/(\d+)\/events$/);
const gateway = settleEdgeGatewayWork(edgeGatewayFixture, gatewayId);
const operation = (gateway?.operations || []).find((entry) => Number(entry.id) === Number(operationId)) || null;
await route.fulfill(json({ data: cloneJson(operation?.events || []) }));
return true;
}
if (/\/edge-gateways\/\d+\/operations$/.test(pathname) && method === "POST") {
const gatewayId = extractMatchId(/\/edge-gateways\/(\d+)\/operations$/);
const gateway = findGateway(gatewayId);
const body = request.postDataJSON?.() || {};
if (!gateway) {
await route.fulfill(json({ message: "Gateway not found" }, 404));
return true;
}
const operationType = String(body.type || "").toUpperCase();
const operationRequest = body.request || {};
const now = toSqlDateTime();
let operation = null;
if (operationType === "DISCOVERY") {
gateway.discovery_status = "PENDING";
operation = createOperation(gateway, "DISCOVERY", operationRequest, {
status: "IN_PROGRESS",
started_at: now,
updated_at: now,
summary: { label: "Gateway is processing the operation", progress: 20, retryable: true },
events: [
{ id: edgeGatewayFixture.nextOperationEventId++, level: "INFO", code: "OPERATION_QUEUED", message: "Operation queued for gateway execution", created_at: now },
{ id: edgeGatewayFixture.nextOperationEventId++, level: "INFO", code: "OPERATION_STARTED", message: "Gateway started processing the operation", created_at: now },
],
});
edgeGatewayFixture.pendingDiscoveryByGatewayId[gatewayId] = {
operationId: operation.id,
fetchCount: 0,
device: {
id: (gateway.inventory?.length || 0) + 1,
device_id: "shelly-plus-new",
local_ip: "10.1.0.33",
model: "Shelly Plus 1PM",
channel_count: 1,
online: true,
capabilities: { generation: 2 },
},
};
} else if (operationType === "UPDATE") {
gateway.target_version = String(operationRequest.target_version || gateway.target_version || "");
gateway.installed_version = gateway.target_version;
operation = createOperation(gateway, "UPDATE", operationRequest, {
status: "COMPLETED",
started_at: now,
completed_at: now,
updated_at: now,
summary: { label: "Completed", progress: 100, retryable: true },
result: { installed_version: gateway.installed_version, target_version: gateway.target_version, restart_required: true },
events: [
{ id: edgeGatewayFixture.nextOperationEventId++, level: "INFO", code: "OPERATION_QUEUED", message: "Operation queued for gateway execution", created_at: now },
{ id: edgeGatewayFixture.nextOperationEventId++, level: "INFO", code: "OPERATION_COMPLETED", message: "Operation completed successfully", created_at: now },
],
});
} else if (operationType === "UNINSTALL") {
gateway.status = "OFFLINE";
gateway.metadata = {
...(gateway.metadata || {}),
uninstalled_at: now,
};
operation = createOperation(gateway, "UNINSTALL", operationRequest, {
status: "COMPLETED",
started_at: now,
completed_at: now,
updated_at: now,
summary: { label: "Completed", progress: 100, retryable: false },
result: { uninstalled: true, manual_cleanup_required: true },
events: [
{ id: edgeGatewayFixture.nextOperationEventId++, level: "INFO", code: "OPERATION_QUEUED", message: "Operation queued for gateway execution", created_at: now },
{ id: edgeGatewayFixture.nextOperationEventId++, level: "INFO", code: "OPERATION_COMPLETED", message: "Operation completed successfully", created_at: now },
],
});
} else {
await route.fulfill(json({ data: { message: "Unsupported gateway operation type", error_code: "EDGE_GATEWAY_VALIDATION_FAILED" } }, 422));
return true;
}
gateway.audit_logs = [
{ id: Date.now(), created_at: now, action: "GATEWAY_OPERATION_QUEUED", actor_type: "USER" },
...(gateway.audit_logs || []),
];
Object.assign(gateway, buildEdgeGatewayRuntimeFixture(gateway));
await route.fulfill(json({ data: { operation: cloneJson(operation), gateway: buildHttpEdgeGatewayGateway(edgeGatewayFixture, gateway, true) } }, 201));
return true;
}
if (/\/edge-gateways\/\d+\/rotate-credentials$/.test(pathname) && method === "POST") {
const gatewayId = extractMatchId(/\/edge-gateways\/(\d+)\/rotate-credentials$/);
const gateway = findGateway(gatewayId);
if (!gateway) {
await route.fulfill(json({ message: "Gateway not found" }, 404));
return true;
}
const rotatedAt = toSqlDateTime();
gateway.metadata = {
...(gateway.metadata || {}),
credentials_rotated_at: rotatedAt,
};
gateway.audit_logs = [
{ id: Date.now(), created_at: rotatedAt, action: "GATEWAY_CREDENTIALS_ROTATED", actor_type: "USER" },
...(gateway.audit_logs || []),
];
Object.assign(gateway, buildEdgeGatewayRuntimeFixture(gateway));
await route.fulfill(
json({
data: {
gateway_id: gatewayId,
rotated_at: rotatedAt,
agent_token: "rotated-edge-agent-token",
config_json: JSON.stringify(
{
apiUrl: "https://api.truckwash.test",
gatewayId,
agentToken: "rotated-edge-agent-token",
installDir: "/opt/truckwash-edge-agent",
serviceName: "truckwash-edge-agent.service",
heartbeatIntervalSeconds: 15,
operationPollTimeoutSeconds: 20,
},
null,
2
),
restart_instructions: [
"sudo systemctl restart truckwash-edge-agent.service",
"sudo systemctl status truckwash-edge-agent.service --no-pager",
],
},
})
);
return true;
}
if (/\/edge-gateways\/\d+\/discovery$/.test(pathname) && method === "POST") {
const gatewayId = extractMatchId(/\/edge-gateways\/(\d+)\/discovery$/);
const gateway = findGateway(gatewayId);
if (gateway) {
const commandId = Date.now();
const now = toSqlDateTime();
const operation = createOperation(gateway, "DISCOVERY", {}, {
status: "IN_PROGRESS",
started_at: now,
updated_at: now,
summary: { label: "Gateway is processing the operation", progress: 20, retryable: true },
events: [
{ id: edgeGatewayFixture.nextOperationEventId++, level: "INFO", code: "OPERATION_QUEUED", message: "Operation queued for gateway execution", created_at: now },
{ id: edgeGatewayFixture.nextOperationEventId++, level: "INFO", code: "OPERATION_STARTED", message: "Gateway started processing the operation", created_at: now },
],
});
gateway.discovery_status = "PENDING";
gateway.recent_commands = [
{
id: commandId,
command_type: "DISCOVER_SHELLY",
status: "PENDING",
created_at: toSqlDateTime(),
requested_at: toSqlDateTime(),
},
...(gateway.recent_commands || []),
];
edgeGatewayFixture.pendingDiscoveryByGatewayId[gatewayId] = {
jobId: commandId,
operationId: operation.id,
fetchCount: 0,
device: {
id: (gateway.inventory?.length || 0) + 1,
@@ -2497,11 +2631,7 @@ async function handleEdgeGatewayRoute({
Object.assign(gateway, buildEdgeGatewayRuntimeFixture(gateway));
}
await route.fulfill(
gateway
? json({ data: buildHttpEdgeGatewayGateway(edgeGatewayFixture, gateway, true) })
: json({ message: "Gateway not found" }, 404)
);
await route.fulfill(gatewayResponse(gateway, true));
return true;
}
@@ -2560,10 +2690,12 @@ async function handleEdgeGatewayRoute({
];
Object.assign(gateway, buildEdgeGatewayRuntimeFixture(gateway));
edgeGatewayFixture.gateways = edgeGatewayFixture.gateways.map((item) => (Number(item.id) === Number(gateway.id) ? Object.assign(item, gateway) : item));
edgeGatewayFixture.gateways = edgeGatewayFixture.gateways.map((item) =>
Number(item.id) === Number(gateway.id) ? Object.assign(item, gateway) : item
);
}
await route.fulfill(gateway ? json({ data: buildHttpEdgeGatewayGateway(edgeGatewayFixture, gateway, true) }) : json({ message: "Gateway not found" }, 404));
await route.fulfill(gatewayResponse(gateway, true));
return true;
}
@@ -2583,6 +2715,11 @@ async function handleEdgeGatewayRoute({
return true;
}
if (/\/edge-gateways\/\d+\/(?:update-jobs|uninstall)(?:\/.*)?$/.test(pathname) || /\/edge-gateways\/\d+\/shell-sessions(?:\/.*)?$/.test(pathname)) {
await route.fulfill(json({ message: "Route not found" }, 404));
return true;
}
if (/\/edge-gateways\/\d+$/.test(pathname) && method === "DELETE") {
const gatewayId = Number(pathname.split("/").pop());
const gateway = findGateway(gatewayId);
@@ -2761,6 +2898,11 @@ export async function mockApi(page, options = {}) {
display_name: "E2E User",
permissions: options.permissions || ["user"],
economic_customer: [],
runtime_config: {
economic: {
transaction_draft_customer_number: null,
},
},
};
const sessionData = {