From 072a05ab4205a55b5335e5765a0ac9e8dfbe8bc1 Mon Sep 17 00:00:00 2001 From: Gareth George Date: Wed, 20 Dec 2023 19:12:17 +0000 Subject: [PATCH] feat: add activity bar to UI heading --- internal/oplog/oplog.go | 4 +-- webui/src/components/ActivityBar.tsx | 41 ++++++++++++++++++++++++++++ webui/src/views/App.tsx | 5 ++++ 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 webui/src/components/ActivityBar.tsx diff --git a/internal/oplog/oplog.go b/internal/oplog/oplog.go index 16929443..791da7e0 100644 --- a/internal/oplog/oplog.go +++ b/internal/oplog/oplog.go @@ -97,8 +97,8 @@ func (o *OpLog) Scan(onIncomplete func(op *v1.Operation)) error { continue } - if op.Status == v1.OperationStatus_STATUS_PENDING || op.Status == v1.OperationStatus_STATUS_SYSTEM_CANCELLED { - // remove pending operations. + if op.Status == v1.OperationStatus_STATUS_PENDING || op.Status == v1.OperationStatus_STATUS_SYSTEM_CANCELLED || op.Status == v1.OperationStatus_STATUS_USER_CANCELLED { + // remove pending or user cancelled operations. o.deleteOperationHelper(tx, op.Id) continue } else if op.Status == v1.OperationStatus_STATUS_INPROGRESS { diff --git a/webui/src/components/ActivityBar.tsx b/webui/src/components/ActivityBar.tsx new file mode 100644 index 00000000..cbf5996e --- /dev/null +++ b/webui/src/components/ActivityBar.tsx @@ -0,0 +1,41 @@ +import React, { useEffect, useState } from "react"; +import { EOperation, detailsForOperation, displayTypeToString, getTypeForDisplay, subscribeToOperations, toEop, unsubscribeFromOperations } from "../state/oplog"; +import { OperationEvent, OperationStatus } from "../../gen/ts/v1/operations.pb"; +import { formatDuration } from "../lib/formatting"; + +export const ActivityBar = () => { + const [activeOperations, setActiveOperations] = useState([]); + + useEffect(() => { + const callback = ({ operation, type }: OperationEvent) => { + if (!operation || !type) return; + + setActiveOperations((ops) => { + ops = ops.filter((op) => op.id !== operation.id); + if (operation.status === OperationStatus.STATUS_INPROGRESS) { + ops.push(toEop(operation)); + } + ops.sort((a, b) => b.parsedTime - a.parsedTime); + return ops; + }); + } + + subscribeToOperations(callback); + + return () => { + unsubscribeFromOperations(callback); + } + }); + + const details = activeOperations.map((op) => { + return { + op: op, + details: detailsForOperation(op), + displayName: displayTypeToString(getTypeForDisplay(op)), + } + }); + + return {details.map(details => { + return <>{details.displayName} in progress for plan {details.op.planId} to {details.op.repoId} for {formatDuration(details.details.duration)} + })} +} \ No newline at end of file diff --git a/webui/src/views/App.tsx b/webui/src/views/App.tsx index f4334519..72b2139b 100644 --- a/webui/src/views/App.tsx +++ b/webui/src/views/App.tsx @@ -16,6 +16,7 @@ import { useShowModal } from "../components/ModalManager"; import { MainContentArea, useSetContent } from "./MainContentArea"; import { AddPlanModal } from "./AddPlanModal"; import { uiBuildVersion } from "../state/buildcfg"; +import { ActivityBar } from "../components/ActivityBar"; const { Header, Sider } = Layout; @@ -67,6 +68,10 @@ export const App: React.FC = () => { {uiBuildVersion} + + + +