From 38ec36b2374527240d2f2a4b2bd81b4db6360e41 Mon Sep 17 00:00:00 2001 From: "Bryson G." <114206517+bryson-g@users.noreply.github.com> Date: Sat, 22 Feb 2025 20:38:18 -0800 Subject: [PATCH 1/4] feat(dashboard): use selectionlink (#1329) --- .../[tenantId]/components/VersionTag.tsx | 9 +++++++++ .../tables/ExternalEventDefTable.tsx | 9 ++++----- .../components/tables/TaskDefTable.tsx | 10 ++++------ .../components/tables/UserTaskDefTable.tsx | 18 ++++++------------ .../components/tables/WfSpecTable.tsx | 19 ++++++------------- .../tables/WorkflowEventDefTable.tsx | 9 ++++----- 6 files changed, 33 insertions(+), 41 deletions(-) create mode 100644 dashboard/src/app/(authenticated)/[tenantId]/components/VersionTag.tsx diff --git a/dashboard/src/app/(authenticated)/[tenantId]/components/VersionTag.tsx b/dashboard/src/app/(authenticated)/[tenantId]/components/VersionTag.tsx new file mode 100644 index 000000000..db73143b3 --- /dev/null +++ b/dashboard/src/app/(authenticated)/[tenantId]/components/VersionTag.tsx @@ -0,0 +1,9 @@ +import { TagIcon } from "lucide-react"; + +export default function VersionTag({ label }: { label: string }) { + return ( +
+ {label} +
+ ) +} \ No newline at end of file diff --git a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/ExternalEventDefTable.tsx b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/ExternalEventDefTable.tsx index f267f2c41..fbd75a5ba 100644 --- a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/ExternalEventDefTable.tsx +++ b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/ExternalEventDefTable.tsx @@ -2,6 +2,7 @@ import { ExternalEventDefId } from 'littlehorse-client/proto' import LinkWithTenant from '../LinkWithTenant' import { FC, Fragment } from 'react' import { SearchResultProps } from '.' +import { SelectionLink } from '../SelectionLink' export const ExternalEventDefTable: FC = ({ pages = [] }) => { if (pages.length === 0) { @@ -13,11 +14,9 @@ export const ExternalEventDefTable: FC = ({ pages = [] }) => {pages.map((page, i) => ( {page.results.map(({ name }: ExternalEventDefId) => ( -
- - {name} - -
+ +

{name}

+
))}
))} diff --git a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/TaskDefTable.tsx b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/TaskDefTable.tsx index 69626ff19..04fad463b 100644 --- a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/TaskDefTable.tsx +++ b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/TaskDefTable.tsx @@ -2,7 +2,7 @@ import { TaskDefId } from 'littlehorse-client/proto' import { FC, Fragment } from 'react' import { SearchResultProps } from '.' import { useParams } from 'next/navigation' -import LinkWithTenant from '../LinkWithTenant' +import { SelectionLink } from '../SelectionLink' export const TaskDefTable: FC = ({ pages = [] }) => { const { tenantId } = useParams() @@ -16,11 +16,9 @@ export const TaskDefTable: FC = ({ pages = [] }) => { {pages.map((page, i) => ( {page.results.map(({ name }: TaskDefId) => ( -
- - {name} - -
+ +

{name}

+
))}
))} diff --git a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/UserTaskDefTable.tsx b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/UserTaskDefTable.tsx index 84c9b2eb7..d6900ad29 100644 --- a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/UserTaskDefTable.tsx +++ b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/UserTaskDefTable.tsx @@ -1,9 +1,9 @@ import { Separator } from '@/components/ui/separator' import { UserTaskDefId } from 'littlehorse-client/proto' -import { TagIcon } from 'lucide-react' import { FC, Fragment } from 'react' import { SearchResultProps } from '.' -import LinkWithTenant from '../LinkWithTenant' +import { SelectionLink } from '../SelectionLink' +import VersionTag from '../VersionTag' export const UserTaskDefTable: FC = ({ pages = [] }) => { if (pages.length === 0) { @@ -15,16 +15,10 @@ export const UserTaskDefTable: FC = ({ pages = [] }) => { {pages.map((page, i) => ( {page.results.map(({ name, version }: UserTaskDefId) => ( - -
- - {name} - -
- v{version} -
-
-
+ +

{name}

+ +
))}
))} diff --git a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WfSpecTable.tsx b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WfSpecTable.tsx index f417546dc..e06588505 100644 --- a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WfSpecTable.tsx +++ b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WfSpecTable.tsx @@ -1,12 +1,11 @@ import { getLatestWfSpecs } from '@/app/actions/getLatestWfSpec' -import { Separator } from '@/components/ui/separator' import { WfSpecData } from '@/types' -import { TagIcon } from 'lucide-react' import { useParams, useRouter } from 'next/navigation' -import { FC, Fragment, useEffect, useState } from 'react' +import { FC, useEffect, useState } from 'react' import { SearchResultProps } from '.' import { SelectionLink } from '../SelectionLink' +import VersionTag from '../VersionTag' export const WfSpecTable: FC = ({ pages = [] }) => { const router = useRouter() const tenantId = useParams().tenantId as string @@ -25,16 +24,10 @@ export const WfSpecTable: FC = ({ pages = [] }) => {
{wfSpecs.map(wfSpec => ( - - -

{wfSpec.name}

-
- - Latest: v{wfSpec.latestVersion} -
-
- -
+ +

{wfSpec.name}

+ +
))}
diff --git a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WorkflowEventDefTable.tsx b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WorkflowEventDefTable.tsx index 5e60506b2..4a7d09477 100644 --- a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WorkflowEventDefTable.tsx +++ b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WorkflowEventDefTable.tsx @@ -3,6 +3,7 @@ import { FC, Fragment } from 'react' import { SearchResultProps } from '.' import { useParams } from 'next/navigation' import LinkWithTenant from '../LinkWithTenant' +import { SelectionLink } from '../SelectionLink' export const WorkflowEventDefTable: FC = ({ pages = [] }) => { const { tenantId } = useParams() @@ -16,11 +17,9 @@ export const WorkflowEventDefTable: FC = ({ pages = [] }) => {pages.map((page, i) => ( {page.results.map(({ name }: WorkflowEventDefId) => ( -
- - {name} - -
+ +

{name}

+
))}
))} From 83d13a6bda6a7d8b78e499b86b9795dd794bad66 Mon Sep 17 00:00:00 2001 From: "Bryson G." <114206517+bryson-g@users.noreply.github.com> Date: Sat, 22 Feb 2025 21:10:56 -0800 Subject: [PATCH 2/4] fix: conditionally render sign out (#1327) --- .../[tenantId]/components/Principal.tsx | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/dashboard/src/app/(authenticated)/[tenantId]/components/Principal.tsx b/dashboard/src/app/(authenticated)/[tenantId]/components/Principal.tsx index 434bd47c7..18b02a4ef 100644 --- a/dashboard/src/app/(authenticated)/[tenantId]/components/Principal.tsx +++ b/dashboard/src/app/(authenticated)/[tenantId]/components/Principal.tsx @@ -1,20 +1,22 @@ -import { useWhoAmI } from '@/contexts/WhoAmIContext' import { DropdownMenu, - DropdownMenuSeparator, - DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, } from '@/components/ui/dropdown-menu' +import { useWhoAmI } from '@/contexts/WhoAmIContext' import { signOut } from 'next-auth/react' -import { FC, Fragment } from 'react' +import { FC } from 'react' function classNames(...classes: Array) { return classes.filter(Boolean).join(' ') } export const Principal: FC = () => { const { user } = useWhoAmI() + const isAuthEnabled = process.env.LHD_OAUTH_ENABLED === 'true' + return ( @@ -25,9 +27,11 @@ export const Principal: FC = () => { {user?.name} - signOut()} className="block w-full px-4 py-2 text-left text-sm"> - Sign out - + {isAuthEnabled && ( + signOut()} className="block w-full px-4 py-2 text-left text-sm"> + Sign out + + )} ) From 63d70a8be9600dcf14395db391d9d2f83b0d013e Mon Sep 17 00:00:00 2001 From: "Bryson G." <114206517+bryson-g@users.noreply.github.com> Date: Sat, 22 Feb 2025 21:35:15 -0800 Subject: [PATCH 3/4] fix(dashboard): explicitly state none found (#1328) --- .../src/app/(authenticated)/[tenantId]/components/Search.tsx | 2 +- .../[tenantId]/components/tables/ExternalEventDefTable.tsx | 3 +-- .../[tenantId]/components/tables/TaskDefTable.tsx | 4 ++-- .../[tenantId]/components/tables/UserTaskDefTable.tsx | 3 +-- .../[tenantId]/components/tables/WfSpecTable.tsx | 2 +- .../[tenantId]/components/tables/WorkflowEventDefTable.tsx | 4 ++-- 6 files changed, 8 insertions(+), 10 deletions(-) diff --git a/dashboard/src/app/(authenticated)/[tenantId]/components/Search.tsx b/dashboard/src/app/(authenticated)/[tenantId]/components/Search.tsx index 93440c3c1..188ad0fd7 100644 --- a/dashboard/src/app/(authenticated)/[tenantId]/components/Search.tsx +++ b/dashboard/src/app/(authenticated)/[tenantId]/components/Search.tsx @@ -1,9 +1,9 @@ 'use client' import { SEARCH_DEFAULT_LIMIT, SEARCH_ENTITIES, SearchType } from '@/app/constants' -import useSWRInfinite from 'swr/infinite' import { RefreshCwIcon } from 'lucide-react' import { useParams, useSearchParams } from 'next/navigation' import { FC, useState } from 'react' +import useSWRInfinite from 'swr/infinite' import { SearchFooter } from './SearchFooter' import { SearchHeader } from './SearchHeader' import { SearchResponse, search } from './searchAction' diff --git a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/ExternalEventDefTable.tsx b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/ExternalEventDefTable.tsx index fbd75a5ba..0b68db321 100644 --- a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/ExternalEventDefTable.tsx +++ b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/ExternalEventDefTable.tsx @@ -1,11 +1,10 @@ import { ExternalEventDefId } from 'littlehorse-client/proto' -import LinkWithTenant from '../LinkWithTenant' import { FC, Fragment } from 'react' import { SearchResultProps } from '.' import { SelectionLink } from '../SelectionLink' export const ExternalEventDefTable: FC = ({ pages = [] }) => { - if (pages.length === 0) { + if (pages.every(page => page.results.length === 0)) { return
No ExternalEventDefs
} diff --git a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/TaskDefTable.tsx b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/TaskDefTable.tsx index 04fad463b..57da5c5b6 100644 --- a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/TaskDefTable.tsx +++ b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/TaskDefTable.tsx @@ -1,13 +1,13 @@ import { TaskDefId } from 'littlehorse-client/proto' +import { useParams } from 'next/navigation' import { FC, Fragment } from 'react' import { SearchResultProps } from '.' -import { useParams } from 'next/navigation' import { SelectionLink } from '../SelectionLink' export const TaskDefTable: FC = ({ pages = [] }) => { const { tenantId } = useParams() - if (pages.length === 0) { + if (pages.every(page => page.results.length === 0)) { return
No TaskDefs
} diff --git a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/UserTaskDefTable.tsx b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/UserTaskDefTable.tsx index d6900ad29..7ba79ac8a 100644 --- a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/UserTaskDefTable.tsx +++ b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/UserTaskDefTable.tsx @@ -1,4 +1,3 @@ -import { Separator } from '@/components/ui/separator' import { UserTaskDefId } from 'littlehorse-client/proto' import { FC, Fragment } from 'react' import { SearchResultProps } from '.' @@ -6,7 +5,7 @@ import { SelectionLink } from '../SelectionLink' import VersionTag from '../VersionTag' export const UserTaskDefTable: FC = ({ pages = [] }) => { - if (pages.length === 0) { + if (pages.every(page => page.results.length === 0)) { return
No UserTaskDefs
} diff --git a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WfSpecTable.tsx b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WfSpecTable.tsx index e06588505..db63d11ce 100644 --- a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WfSpecTable.tsx +++ b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WfSpecTable.tsx @@ -16,7 +16,7 @@ export const WfSpecTable: FC = ({ pages = [] }) => { getLatestWfSpecs(tenantId, wfSpecNames).then(setWfSpecs) }, [pages, tenantId]) - if (pages.length === 0) { + if (pages.every(page => page.results.length === 0)) { return
No WfSpecs
} diff --git a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WorkflowEventDefTable.tsx b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WorkflowEventDefTable.tsx index 4a7d09477..1e4767187 100644 --- a/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WorkflowEventDefTable.tsx +++ b/dashboard/src/app/(authenticated)/[tenantId]/components/tables/WorkflowEventDefTable.tsx @@ -1,14 +1,14 @@ import { WorkflowEventDefId } from 'littlehorse-client/proto' +import { useParams } from 'next/navigation' import { FC, Fragment } from 'react' import { SearchResultProps } from '.' -import { useParams } from 'next/navigation' import LinkWithTenant from '../LinkWithTenant' import { SelectionLink } from '../SelectionLink' export const WorkflowEventDefTable: FC = ({ pages = [] }) => { const { tenantId } = useParams() - if (pages.length === 0) { + if (pages.every(page => page.results.length === 0)) { return
No WorkflowEventDefs
} From a0484cff44f13c24a73de7a079a24fa580f33745 Mon Sep 17 00:00:00 2001 From: "Bryson G." <114206517+bryson-g@users.noreply.github.com> Date: Sun, 23 Feb 2025 11:21:05 -0800 Subject: [PATCH 4/4] refactor(dashboard): code font (#1326) --- .../components/NodeTypes/Task/TaskDetails.tsx | 2 +- .../[tenantId]/components/OverflowText.tsx | 14 +- dashboard/src/app/(authenticated)/layout.tsx | 6 +- dashboard/tailwind.config.ts | 173 +++++++++--------- 4 files changed, 99 insertions(+), 96 deletions(-) diff --git a/dashboard/src/app/(authenticated)/[tenantId]/(diagram)/components/NodeTypes/Task/TaskDetails.tsx b/dashboard/src/app/(authenticated)/[tenantId]/(diagram)/components/NodeTypes/Task/TaskDetails.tsx index e34de7924..5e4e15a26 100644 --- a/dashboard/src/app/(authenticated)/[tenantId]/(diagram)/components/NodeTypes/Task/TaskDetails.tsx +++ b/dashboard/src/app/(authenticated)/[tenantId]/(diagram)/components/NodeTypes/Task/TaskDetails.tsx @@ -84,7 +84,7 @@ export const TaskDetails: FC<{ } -
+
diff --git a/dashboard/src/app/(authenticated)/[tenantId]/components/OverflowText.tsx b/dashboard/src/app/(authenticated)/[tenantId]/components/OverflowText.tsx index c25e67c0a..28192f498 100644 --- a/dashboard/src/app/(authenticated)/[tenantId]/components/OverflowText.tsx +++ b/dashboard/src/app/(authenticated)/[tenantId]/components/OverflowText.tsx @@ -1,11 +1,11 @@ 'use client' -import { FC, useEffect, useRef, useState } from 'react' -import { cn } from '@/components/utils' +import { tryFormatAsJson } from '@/app/utils/tryFormatAsJson' import { Button } from '@/components/ui/button' -import { ChevronRight } from 'lucide-react' import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog' +import { cn } from '@/components/utils' +import { ChevronRight } from 'lucide-react' +import { FC, useEffect, useRef, useState } from 'react' import { CopyButton } from './CopyButton' -import { tryFormatAsJson } from '@/app/utils/tryFormatAsJson' type OverflowTextProps = { text: string @@ -37,7 +37,7 @@ export const OverflowText: FC = ({ text, className, variant } className )} > - {formattedText} + {formattedText}
View @@ -51,14 +51,14 @@ export const OverflowText: FC = ({ text, className, variant } 'bg-status-failed text-red-500': variant === 'error', })} > -
{formattedText}
+
{formattedText}
) } return ( -
+
{formattedText}
) diff --git a/dashboard/src/app/(authenticated)/layout.tsx b/dashboard/src/app/(authenticated)/layout.tsx index 29484f8fe..e610db672 100644 --- a/dashboard/src/app/(authenticated)/layout.tsx +++ b/dashboard/src/app/(authenticated)/layout.tsx @@ -2,11 +2,11 @@ import { Toaster } from '@/components/ui/sonner' import { WhoAmIContext } from '@/contexts/WhoAmIContext' import type { Metadata } from 'next' import { Inter } from 'next/font/google' -import { Header } from './[tenantId]/components/Header' -import { QueryProvider } from './[tenantId]/components/QueryProvider' +import { SWRConfig } from 'swr' import getWhoAmI from '../getWhoami' import '../globals.css' -import { SWRConfig } from 'swr' +import { Header } from './[tenantId]/components/Header' +import { QueryProvider } from './[tenantId]/components/QueryProvider' const inter = Inter({ subsets: ['latin'] }) diff --git a/dashboard/tailwind.config.ts b/dashboard/tailwind.config.ts index a24595ffe..668bf3efd 100644 --- a/dashboard/tailwind.config.ts +++ b/dashboard/tailwind.config.ts @@ -5,91 +5,94 @@ const config = { content: ['./pages/**/*.{ts,tsx}', './components/**/*.{ts,tsx}', './app/**/*.{ts,tsx}', './src/**/*.{ts,tsx}'], prefix: '', theme: { - container: { - center: true, - padding: '2rem', - screens: { - '2xl': '1400px' - } - }, - extend: { - colors: { - border: 'hsl(var(--border))', - input: 'hsl(var(--input))', - ring: 'hsl(var(--ring))', - background: 'hsl(var(--background))', - foreground: 'hsl(var(--foreground))', - primary: { - DEFAULT: 'hsl(var(--primary))', - foreground: 'hsl(var(--primary-foreground))' - }, - secondary: { - DEFAULT: 'hsl(var(--secondary))', - foreground: 'hsl(var(--secondary-foreground))' - }, - destructive: { - DEFAULT: 'hsl(var(--destructive))', - foreground: 'hsl(var(--destructive-foreground))' - }, - muted: { - DEFAULT: 'hsl(var(--muted))', - foreground: 'hsl(var(--muted-foreground))' - }, - accent: { - DEFAULT: 'hsl(var(--accent))', - foreground: 'hsl(var(--accent-foreground))' - }, - popover: { - DEFAULT: 'hsl(var(--popover))', - foreground: 'hsl(var(--popover-foreground))' - }, - card: { - DEFAULT: 'hsl(var(--card))', - foreground: 'hsl(var(--card-foreground))' - }, - status: { - running: 'theme("colors.blue.300")', - success: 'theme("colors.green.300")', - failed: 'theme("colors.red.300")', - exception: 'theme("colors.orange.300")', - halting: 'theme("colors.purple.300")' - }, - chart: { - '1': 'hsl(var(--chart-1))', - '2': 'hsl(var(--chart-2))', - '3': 'hsl(var(--chart-3))', - '4': 'hsl(var(--chart-4))', - '5': 'hsl(var(--chart-5))' - } - }, - borderRadius: { - lg: 'var(--radius)', - md: 'calc(var(--radius) - 2px)', - sm: 'calc(var(--radius) - 4px)' - }, - keyframes: { - 'accordion-down': { - from: { - height: '0' - }, - to: { - height: 'var(--radix-accordion-content-height)' - } - }, - 'accordion-up': { - from: { - height: 'var(--radix-accordion-content-height)' - }, - to: { - height: '0' - } - } - }, - animation: { - 'accordion-down': 'accordion-down 0.2s ease-out', - 'accordion-up': 'accordion-up 0.2s ease-out' - } - } + container: { + center: true, + padding: '2rem', + screens: { + '2xl': '1400px', + }, + }, + extend: { + colors: { + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))', + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))', + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))', + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))', + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))', + }, + status: { + running: 'theme("colors.blue.300")', + success: 'theme("colors.green.300")', + failed: 'theme("colors.red.300")', + exception: 'theme("colors.orange.300")', + halting: 'theme("colors.purple.300")', + }, + chart: { + '1': 'hsl(var(--chart-1))', + '2': 'hsl(var(--chart-2))', + '3': 'hsl(var(--chart-3))', + '4': 'hsl(var(--chart-4))', + '5': 'hsl(var(--chart-5))', + }, + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', + }, + keyframes: { + 'accordion-down': { + from: { + height: '0', + }, + to: { + height: 'var(--radix-accordion-content-height)', + }, + }, + 'accordion-up': { + from: { + height: 'var(--radix-accordion-content-height)', + }, + to: { + height: '0', + }, + }, + }, + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', + }, + fontFamily: { + code: ['Fira Code', 'sans-serif'], + }, + }, }, plugins: [require('tailwindcss-animate')], } satisfies Config