diff --git a/.env.example b/.env.example index 8363c0eb58230719c761fad7e5ce7d2e7b09d9bc..fb4b053b35c897ea641677c43df02dab9d595bc6 100644 --- a/.env.example +++ b/.env.example @@ -1 +1 @@ -REACT_APP_API_BASE_URL=http://localhost:8080/api/v1 \ No newline at end of file +NEXT_PUBLIC_API_BASE_URL=http://localhost:8080/api/v1 \ No newline at end of file diff --git a/src/components/CheckRepoForm.tsx b/src/components/CheckRepoForm.tsx index aa8dfbe74d398d0cb562ea646c33965ef2d20e3e..b4e52cd1897e6e9fa5912091346c605ff89fdbca 100644 --- a/src/components/CheckRepoForm.tsx +++ b/src/components/CheckRepoForm.tsx @@ -32,14 +32,6 @@ const CheckRepoForm: FunctionComponent<Props> = ({ return } setIsPending(true) - // check if valid url - - await new Promise<void>((resolve) => - setTimeout(() => { - console.log('resolved') - resolve() - }, 100000), - ) try { const url = new URL(repositoryUrl) diff --git a/src/components/ResultGrid.tsx b/src/components/ResultGrid.tsx index ab5d58187d28524fcb91c9bc7588800d7754b6ec..65fd5a604f65645f551564d01d854d4f04df4ca2 100644 --- a/src/components/ResultGrid.tsx +++ b/src/components/ResultGrid.tsx @@ -1,3 +1,4 @@ +import Image from 'next/image' import { SarifApiResponse } from '../lib/apiClient' import { cn } from '../lib/utils' import ResultTable from './ResultTable' @@ -39,25 +40,35 @@ export default function ResultGrid({ currentScan }: Props) { ) .map((badge) => ( <div - className="relative bg-gray-400/10 p-6" + className="overflow-hidden bg-gray-400/10 p-10" key={`${badge.badgeId}-${badge.badgeLevel}`} > - <img + <div className="relative aspect-square"> + {!badge.badgeGranted && ( + <div className="absolute right-0 top-0 -translate-y-1/2 translate-x-1/2 rotate-45 bg-red-600 px-10 py-2 font-bold text-white"> + Not granted + </div> + )} + <Image + className={cn( + 'h-40 w-full object-contain', + !badge.badgeGranted && + 'opacity-50', + )} + src={badge.badgeUrl} + fill + alt={badge.badgeId} + /> + </div> + <p className={cn( - 'h-40 w-full object-contain', + 'text-sm', !badge.badgeGranted && - 'opacity-30 grayscale', + 'opacity-50', )} - src={badge.badgeUrl} - alt={badge.badgeId} - /> - {!badge.badgeGranted && ( - <div className="absolute inset-0 top-40 flex flex-col items-center justify-center"> - <p className="text-lg font-semibold"> - Not granted - </p> - </div> - )} + > + {badge.badgeDescription} + </p> </div> ))} </div> diff --git a/src/components/ResultTable.tsx b/src/components/ResultTable.tsx index fdba7d03a2ef3d57374a4a60a6cb4ce5837bdd4a..99ab55abd8d30e49615326c670f276914c7fb222 100644 --- a/src/components/ResultTable.tsx +++ b/src/components/ResultTable.tsx @@ -1,5 +1,7 @@ +import { ChevronDownIcon } from '@heroicons/react/24/outline' import { SarifApiResponse } from '../lib/apiClient' import { cn } from '../lib/utils' +import { Badge } from './ui/badge' const people = [ { @@ -22,79 +24,81 @@ export default function ResultTable({ currentScan }: Props) { .map((badge) => ( <div key={`${badge.badgeId}-${badge.badgeLevel}`} - className="mt-8 rounded-lg bg-gray-100 p-10" + className="mt-8 rounded-lg bg-gray-100 px-4 py-2" > <details className=""> - <summary className="relative text-lg font-medium text-gray-900"> - Details on: {badge.badgeId} {badge.badgeLevel} - <span className="ml-2 inline-block"> - <span className="relative flex size-3"> - <span - className={cn( - 'absolute inline-flex h-full w-full animate-ping rounded-full opacity-75', - badge.badgeGranted - ? 'bg-green-400' - : 'bg-red-400', - )} - ></span> - <span - className={cn( - 'relative inline-flex size-3 rounded-full', - badge.badgeGranted - ? 'bg-green-400' - : 'bg-red-400', - )} - ></span> - </span> + <summary className="relative flex cursor-pointer flex-row justify-between text-lg font-medium text-gray-900"> + <span> + Details on: {badge.badgeId}{' '} + {badge.badgeLevel} + <Badge + variant={ + badge.badgeGranted + ? 'default' + : 'destructive' + } + className="ml-2" + > + {badge.badgeGranted + ? 'Granted' + : 'Not granted'} + </Badge> </span> + + <ChevronDownIcon className="w-5" /> </summary> <div className="mt-8"> - <div className="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> + <div className="overflow-x-aut"> <div className="inline-block min-w-full py-2 align-middle"> - <table className="min-w-full divide-y divide-gray-300"> + <table className="min-w-full divide-y divide-gray-400"> <thead> <tr className="grid grid-cols-6"> <th scope="col" - className="col-span-1 py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6 lg:pl-8" + className="col-span-1 py-3.5 pl-4 pr-3 text-left font-semibold sm:pl-6 lg:pl-8" > Check </th> <th scope="col" - className="col-span-1 px-3 py-3.5 text-left text-sm font-semibold text-gray-900" + className="col-span-1 px-3 py-3.5 text-left font-semibold" > Status </th> <th scope="col" - className="col-span-2 px-3 py-3.5 text-left text-sm font-semibold text-gray-900" + className="col-span-2 px-3 py-3.5 text-left font-semibold" > Description </th> <th scope="col" - className="col-span-2 px-3 py-3.5 text-left text-sm font-semibold text-gray-900" + className="col-span-2 px-3 py-3.5 text-left font-semibold" > Evidence </th> </tr> </thead> - <tbody className="divide-y divide-gray-200"> + <tbody className="divide-y divide-gray-300"> {badge.badgeExplanation.criteria.map( (criteria) => ( <tr key={`${badge.badgeId}-${badge.badgeLevel}-${criteria.ruleId}`} className="grid grid-cols-6" > - <td className="col-span-1 whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 lg:pl-8"> + <td + title={ + criteria.ruleId + } + className="col-span-1 overflow-hidden overflow-ellipsis whitespace-nowrap py-4 pl-4 pr-3 font-medium text-gray-900 sm:pl-6 lg:pl-8" + > { criteria.ruleId.split( ':', )[0] } </td> - <td className="col-span-1 whitespace-nowrap px-3 py-4 text-sm text-gray-500"> + <td className="col-span-1 whitespace-nowrap px-3 py-4"> <div className="flex items-center justify-end gap-x-2 sm:justify-start"> <span className="relative flex size-2"> <span @@ -122,19 +126,19 @@ export default function ResultTable({ currentScan }: Props) { )} ></span> </span> - <div className="hidden text-black sm:block"> + <div className="hidden sm:block"> { criteria.status } </div> </div> </td> - <td className="col-span-2 px-3 py-4 text-sm text-gray-500"> + <td className="col-span-2 px-3 py-4"> { criteria.description } </td> - <td className="col-span-2 px-3 py-4 text-sm text-gray-500"> + <td className="col-span-2 px-3 py-4"> { criteria.evidence } diff --git a/src/lib/apiClient.ts b/src/lib/apiClient.ts index 27443bda836c36627f7bae261c09b969b9cfbb78..366460d626ccb08d0c1e5ad10657fb6e3f728275 100644 --- a/src/lib/apiClient.ts +++ b/src/lib/apiClient.ts @@ -16,6 +16,7 @@ export interface Badge { badgeInformationUri: string badgeExplanation: BadgeExplanation badgeGranted: boolean + badgeDescription: string } export interface BadgeExplanation { diff --git a/tailwind.config.js b/tailwind.config.js index 6dd9d759964821cc9a5b715fb866bd6073797b17..1aaa7721385a87532bdee0c77d9b54463d34a13a 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -25,6 +25,21 @@ module.exports = { 900: '#0c5550', 950: '#003433', }, + primary: { + DEFAULT: '#2f6eff', + foreground: "#FFFFFF", + 50: '#e8f5ff', + 100: '#d5edff', + 200: '#b3dbff', + 300: '#85c1ff', + 400: '#5698ff', + 500: '#2f6eff', + 600: '#0c3fff', + 700: '#1544ff', + 800: '#0631cd', + 900: '#10329f', + 950: '#0a1c5c', + }, blue: { 50: '#e8f5ff', 100: '#d5edff', @@ -38,6 +53,10 @@ module.exports = { 900: '#10329f', 950: '#0a1c5c', }, + destructive: { + DEFAULT: "#E71507", + foreground: "#FFFFFF", + } }, } },