Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dashboard): taskRun Table #829

Merged
merged 14 commits into from
May 27, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const Diagram: FC<Props> = ({ spec, wfRun }) => {

const searchParams: ReadonlyURLSearchParams = useSearchParams()
const threadRunNumberFromRedirection: number = Number(searchParams.get('threadRunNumber'))
const nodeRunNameToBeHighlighted: string = searchParams.get('nodeRunName')!
const nodeNameToBeHighlighted: string = searchParams.get('nodeName')!
HazimAr marked this conversation as resolved.
Show resolved Hide resolved

let threadToShowByDefault = determineDefaultThreadRun(currentThread, wfRun, threadRunNumberFromRedirection, spec)

Expand Down Expand Up @@ -98,7 +98,7 @@ export const Diagram: FC<Props> = ({ spec, wfRun }) => {
>
<Controls />
</ReactFlow>
<Layouter nodeRuns={threadNodeRuns} nodeRunNameToBeHighlighted={nodeRunNameToBeHighlighted} />
<Layouter nodeRuns={threadNodeRuns} nodeNameToBeHighlighted={nodeNameToBeHighlighted} />
</div>
</ThreadProvider>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { NodeRun } from 'littlehorse-client/dist/proto/node_run'
import { FC, useCallback, useEffect } from 'react'
import { Edge, Node, useReactFlow, useStore } from 'reactflow'

export const Layouter: FC<{ nodeRuns?: NodeRun[]; nodeRunNameToBeHighlighted?: string }> = ({
export const Layouter: FC<{ nodeRuns?: NodeRun[]; nodeNameToBeHighlighted?: string }> = ({
nodeRuns,
nodeRunNameToBeHighlighted,
nodeNameToBeHighlighted,
}) => {
const nodes = useStore(store => store.getNodes())
const edges = useStore(store => store.edges)
Expand Down Expand Up @@ -33,7 +33,7 @@ export const Layouter: FC<{ nodeRuns?: NodeRun[]; nodeRunNameToBeHighlighted?: s
return nodeRun.nodeName === node.id
})
const fade = nodeRuns !== undefined && nodeRun === undefined
const nodeNeedsToBeHighlighted = node.id === nodeRunNameToBeHighlighted
const nodeNeedsToBeHighlighted = node.id === nodeNameToBeHighlighted

return {
...node,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use server'
import { lhClient } from '@/app/lhClient'
import { WithTenant } from '@/types'
import { NodeRun } from 'littlehorse-client/dist/proto/node_run'
import { TaskRunId } from 'littlehorse-client/dist/proto/object_id';
import { SearchTaskRunRequest, TaskRunIdList } from 'littlehorse-client/dist/proto/service'
import { TaskRun } from 'littlehorse-client/dist/proto/task_run'

export interface runDetails {
taskRun: TaskRun
nodeRun: NodeRun
}
export interface PaginatedTaskRunList extends TaskRunIdList {
resultsWithDetails: runDetails[]
bookmarkAsString: string | undefined
}

type WithBookmarkAsString = {
bookmarkAsString: string | undefined
}

export type TaskRunSearchProps = SearchTaskRunRequest & WithTenant & WithBookmarkAsString
export const searchTaskRun = async ({
tenantId,
bookmarkAsString,
...req
}: TaskRunSearchProps): Promise<PaginatedTaskRunList> => {
const client = await lhClient({ tenantId })
const requestWithBookmark = bookmarkAsString ? { ...req, bookmark: Buffer.from(bookmarkAsString, 'base64') } : req
const taskRunIdList: TaskRunIdList = await client.searchTaskRun(requestWithBookmark)
const hydrateWithTaskRunDetails = (): Promise<runDetails>[] => {
return taskRunIdList.results.map(async (taskRunId: TaskRunId) => {
const taskRun = await client.getTaskRun({
wfRunId: taskRunId.wfRunId,
taskGuid: taskRunId.taskGuid,
})
const nodeRun = await client.getNodeRun(taskRun.id!)

return {
taskRun,
nodeRun,
}
})
}

const userTaskRunWithDetails: runDetails[] = await Promise.all(hydrateWithTaskRunDetails())
HazimAr marked this conversation as resolved.
Show resolved Hide resolved

return {
...taskRunIdList,
bookmarkAsString: taskRunIdList.bookmark?.toString('base64'),
resultsWithDetails: userTaskRunWithDetails,
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,152 @@
import { Navigation } from '@/app/(authenticated)/components/Navigation'
import { TaskDef as TaskDefProto } from 'littlehorse-client/dist/proto/task_def'
import { FC } from 'react'
import { Details } from './Details'
import { InputVars } from './InputVars'
'use client'
import { Navigation } from '@/app/(authenticated)/components/Navigation';
import { concatWfRunIds, localDateTimeToUTCIsoString, utcToLocalDateTime } from '@/app/utils';
import { useWhoAmI } from '@/contexts/WhoAmIContext';
import { Field, Input, Label } from '@headlessui/react';
import { ArrowPathIcon } from '@heroicons/react/24/outline';
import { useInfiniteQuery } from '@tanstack/react-query';
import { TaskStatus } from 'littlehorse-client/dist/proto/common_enums';
import { TaskDef as TaskDefProto } from 'littlehorse-client/dist/proto/task_def';
import Link from 'next/link';
import { FC, Fragment, useState } from 'react';
import { PaginatedTaskRunList, searchTaskRun } from '../actions/searchTaskRun';
import { Details } from './Details';
import { InputVars } from './InputVars';

type Props = {
spec: TaskDefProto
}
export const TaskDef: FC<Props> = ({ spec }) => {
const [selectedStatus, setSelectedStatus] = useState<TaskStatus | 'ALL'>('ALL')
const [createdAfter, setCreatedAfter] = useState('')
const [createdBefore, setCreatedBefore] = useState('')
const { tenantId } = useWhoAmI()

const { isPending, data, hasNextPage, fetchNextPage } = useInfiniteQuery({
queryKey: ['taskRun', selectedStatus, tenantId, 10, createdAfter, createdBefore],
initialPageParam: undefined,
getNextPageParam: (lastPage: PaginatedTaskRunList) => lastPage.bookmarkAsString,
queryFn: async ({ pageParam }) => {
return await searchTaskRun({
tenantId,
bookmarkAsString: pageParam,
limit: 10,
status: selectedStatus == 'ALL' ? undefined : selectedStatus,
taskDefName: spec.id?.name || '',
earliestStart: createdAfter ? localDateTimeToUTCIsoString(createdAfter) : undefined,
latestStart: createdBefore ? localDateTimeToUTCIsoString(createdBefore) : undefined,
})
},
})
return (
<>
<Navigation href="/?type=TaskDef" title="Go back to TaskDefs" />
<Details id={spec.id} />
<InputVars inputVars={spec.inputVars} />
<hr className="mt-6" />
<div className="mb-4 mt-6 flex items-center justify-between">
<h2 className="text-2xl font-bold">Related Task Run&apos;s:</h2>
<select
className="rounded border px-2 py-2"
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
setSelectedStatus(e.target.value as TaskStatus)
}}
>
<option>ALL</option>
{Object.keys(TaskStatus)
.filter(status => status != TaskStatus.UNRECOGNIZED)
.map(status => (
<option key={status}>{status}</option>
))}
</select>
</div>
<div className="mb-5 flex max-w-fit items-start justify-between">
<Field className="flex items-center justify-between">
<Label className="block w-1/2 font-bold">Created after:</Label>
<Input
type="datetime-local"
value={createdAfter}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setCreatedAfter(e.target.value)}
className="focus:shadow-outline ml-3 w-full appearance-none rounded border px-3 py-2 leading-tight shadow focus:outline-none"
/>
</Field>

<Field className="ml-10 flex items-center justify-between">
<Label className="block w-1/2 font-bold">Created before:</Label>
<Input
type="datetime-local"
value={createdBefore}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setCreatedBefore(e.target.value)}
className="focus:shadow-outline ml-4 w-full appearance-none rounded border px-3 py-2 leading-tight shadow focus:outline-none"
/>
</Field>
</div>

{isPending ? (
<div className="flex min-h-[360px] items-center justify-center text-center">
<ArrowPathIcon className="h-8 w-8 animate-spin fill-blue-500 stroke-none" />
</div>
) : (
<div className="flex min-h-[360px] flex-col gap-4">
<table className="text-surface min-w-full text-center text-sm font-light">
<thead className="border-b border-neutral-200 bg-neutral-300 font-medium">
<tr>
<td scope="col" className="px-6 py-4">
WfRun Id
</td>
<th scope="col" className="px-6 py-4">
Task GUID
</th>
<th scope="col" className="px-6 py-4">
Creation Date
</th>
</tr>
</thead>
<tbody>
{data?.pages.map((page, i) => (
<Fragment key={i}>
{page.resultsWithDetails.length > 0 ? (
page.resultsWithDetails.map(({ taskRun, nodeRun }) => {
return (
<tr key={taskRun.id?.taskGuid} className="border-b border-neutral-200">
<td className="px-6 py-4">😡
<Link
HazimAr marked this conversation as resolved.
Show resolved Hide resolved
className="py-2 text-blue-500 hover:underline"
target="_blank"
//? Will have to create a new request to get the nodeName to select the node in the diagram 😡 (will do this in the rewrite)
href={`/wfRun/${concatWfRunIds(taskRun.id?.wfRunId!)}?threadRunNumber=${taskRun.source?.taskNode?.nodeRunId?.threadRunNumber || taskRun.source?.userTaskTrigger?.nodeRunId?.threadRunNumber}&nodeName=${taskRun.source?.taskNode?.nodeRunId?.position}-${taskRun.source?.taskNode?.nodeRunId}-TASK`}
HazimAr marked this conversation as resolved.
Show resolved Hide resolved
>
{concatWfRunIds(taskRun.id?.wfRunId!)}
</Link>
</td>
<td className="px-6 py-4">{taskRun.id?.taskGuid}</td>

<td className="px-6 py-4">
{taskRun.scheduledAt ? utcToLocalDateTime(taskRun.scheduledAt) : 'N/A'}
</td>
</tr>
)
})
) : (
<tr>
<td colSpan={5}>No data</td>
</tr>
)}
</Fragment>
))}
</tbody>
</table>
</div>
)}

{/* <div className="mt-6">
<SearchFooter
HazimAr marked this conversation as resolved.
Show resolved Hide resolved
currentLimit={limit}
setLimit={setLimit}
hasNextPage={hasNextPage}
fetchNextPage={fetchNextPage}
/>
</div> */}
</>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export const UserTaskDef: FC<Props> = ({ spec }) => {
<Fields fields={spec.fields} />
<hr className="mt-6" />
<div className="mb-4 mt-6 flex items-center justify-between">
<h2 className="text-2xl font-bold">Related User Task Run&apos;s:</h2>
<h2 className="text-2xl font-bold">Related User Task Runs:</h2>
<div className="flex">
{userTaskPossibleStatuses.map(status => (
<Button
Expand Down Expand Up @@ -170,7 +170,7 @@ export const UserTaskDef: FC<Props> = ({ spec }) => {
<Link
className="py-2 text-blue-500 hover:underline"
target="_blank"
href={`/wfRun/${concatWfRunIds(userTaskRun.id?.wfRunId!)}?threadRunNumber=${userTaskRun.nodeRunId?.threadRunNumber}&nodeRunName=${nodeRun.nodeName}`}
href={`/wfRun/${concatWfRunIds(userTaskRun.id?.wfRunId!)}?threadRunNumber=${userTaskRun.nodeRunId?.threadRunNumber}&nodeName=${nodeRun.nodeName}`}
>
{concatWfRunIds(userTaskRun.id?.wfRunId!)}
</Link>
Expand Down
Loading