make check
This commit is contained in:
		| @ -1343,7 +1343,7 @@ test( | ||||
|  | ||||
|     await test.step('should be shorted by modified initially', async () => { | ||||
|       const lastModifiedButton = page.getByRole('button', { | ||||
|         name: 'Last Modified', | ||||
|         name: 'Age', | ||||
|       }) | ||||
|       await expect(lastModifiedButton).toBeVisible() | ||||
|       await expect(lastModifiedButton.getByLabel('arrow down')).toBeVisible() | ||||
| @ -1364,7 +1364,7 @@ test( | ||||
|  | ||||
|     await test.step('Reverse modified order', async () => { | ||||
|       const lastModifiedButton = page.getByRole('button', { | ||||
|         name: 'Last Modified', | ||||
|         name: 'Age', | ||||
|       }) | ||||
|       await lastModifiedButton.click() | ||||
|       await expect(lastModifiedButton).toBeVisible() | ||||
|  | ||||
| @ -5,7 +5,7 @@ import { useHotkeys } from 'react-hotkeys-hook' | ||||
| import { CustomIcon } from '@src/components/CustomIcon' | ||||
|  | ||||
| import type { Project } from '@src/lib/project' | ||||
| import type { Prompt } from '@src/machines/mlEphantManagerMachine' | ||||
| import type { Prompt } from '@src/lib/prompt' | ||||
|  | ||||
| export type HomeItem = Project | Prompt | ||||
| export type HomeItems = Project[] | Prompt[] | ||||
| @ -17,7 +17,7 @@ export const areHomeItemsProjects = (items: HomeItems): items is Project[] => { | ||||
|  | ||||
| export const areHomeItemsPrompts = (items: HomeItems): items is Prompt[] => { | ||||
|   const item = items[0] | ||||
|   return item !== undefined && typeof item.prompt === 'string' | ||||
|   return item !== undefined && 'prompt' in item | ||||
| } | ||||
|  | ||||
| export function useHomeSearch(initialSearchResults: HomeItems) { | ||||
| @ -34,6 +34,8 @@ export function useHomeSearch(initialSearchResults: HomeItems) { | ||||
|       ? 'name' | ||||
|       : 'prompt' | ||||
|  | ||||
|     // Fuse is not happy with HomeItems | ||||
|     // @ts-expect-error | ||||
|     const fuse = new Fuse(items, { | ||||
|       keys: [{ name: nameKeyToMatchAgainst, weight: 0.7 }], | ||||
|       includeScore: true, | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import ms from 'ms' | ||||
| import { Prompt } from '@src/lib/prompt' | ||||
| import type { Prompt } from '@src/lib/prompt' | ||||
|  | ||||
| interface PromptCardProps extends Prompt { | ||||
|   onAction?: (id: Prompt['id']) => void | ||||
| @ -8,16 +8,27 @@ interface PromptCardProps extends Prompt { | ||||
| } | ||||
|  | ||||
| export const PromptFeedback = (props: { | ||||
|   id: Prompt['id'] | ||||
|   selected: Prompt['feedback'] | ||||
|   onFeedback: (id: Prompt['id'], feedback: Prompt['feedback']) => void | ||||
| }) => { | ||||
|   const cssUp = 'border-green-500' | ||||
|   const cssDown = 'border-red-500' | ||||
|   const cssUp = 'border-green-300' | ||||
|   const cssDown = 'border-red-300' | ||||
|  | ||||
|   return ( | ||||
|     <div className="flex flex-row gap-2"> | ||||
|       <button className={cssUp}>Good</button> | ||||
|       <button className={cssDown}>Bad</button> | ||||
|       <button | ||||
|         onClick={() => props.onFeedback(props.id, 'thumbs_up')} | ||||
|         className={cssUp} | ||||
|       > | ||||
|         Good | ||||
|       </button> | ||||
|       <button | ||||
|         onClick={() => props.onFeedback(props.id, 'thumbs_down')} | ||||
|         className={cssDown} | ||||
|       > | ||||
|         Bad | ||||
|       </button> | ||||
|     </div> | ||||
|   ) | ||||
| } | ||||
| @ -45,8 +56,9 @@ export const PromptCard = (props: PromptCardProps) => { | ||||
|         <div className="w-fit flex flex-col items-end"> | ||||
|           <button onClick={() => props.onDelete?.(props.id)}>Delete</button> | ||||
|           <PromptFeedback | ||||
|             id={props.id} | ||||
|             selected={props.feedback} | ||||
|             onFeedback={props.onFeedback} | ||||
|             onFeedback={(...args) => props.onFeedback?.(...args)} | ||||
|           /> | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import type { Models } from '@kittycad/lib' | ||||
|  | ||||
| export type Prompt = Models['TextToCad_Type'] | ||||
| export type Prompt = Models['TextToCad_type'] | ||||
|  | ||||
| // export interface TextToCad_type { | ||||
| //     code?: string; | ||||
| @ -100,21 +100,22 @@ export const generateFakeSubmittedPrompt = () => ({ | ||||
|   created_at: new Date(Math.random() * 100000000).toISOString(), | ||||
|   error: Math.random().toString(), | ||||
|   // declare type MlFeedback_type = 'thumbs_up' | 'thumbs_down' | 'accepted' | 'rejected'; | ||||
|   feedback: 'thumbs_up', | ||||
|   feedback: 'thumbs_up' as Prompt['feedback'], | ||||
|   id: Math.random().toString(), | ||||
|   kcl_version: Math.random().toString(), | ||||
|   // export declare type TextToCadModel_type = 'cad' | 'kcl' | 'kcl_iteration'; model : 'kcl', | ||||
|   model_version: Math.random().toString(), | ||||
|   // export declare type TextToCadModel_type = 'cad' | 'kcl' | 'kcl_iteration'; model : 'kcl', | ||||
|   model: 'kcl' as Prompt['model'], | ||||
|   // export declare type FileExportFormat_type = 'fbx' | 'glb' | 'gltf' | 'obj' | 'ply' | 'step' | 'stl'; | ||||
|   output_format: 'glb', | ||||
|   output_format: 'glb' as Prompt['output_format'], | ||||
|   outputs: { | ||||
|     [Math.random().toString()]: Math.random().toString(), | ||||
|   }, | ||||
|   prompt: PROMPTS[parseInt((Math.random() * 10).toString()[0])], | ||||
|   started_at: new Date(Math.random()).toISOString(), | ||||
|   // declare type ApiCallStatus_type = 'queued' | 'uploaded' | 'in_progress' | 'completed' | 'failed'; | ||||
|   status: 'completed', | ||||
|   updated_at: Math.random(), | ||||
|   status: 'completed' as Prompt['status'], | ||||
|   updated_at: Math.random().toString(), | ||||
|   // declare type ApiTokenUuid_type = string; | ||||
|   user_id: Math.random().toString(), | ||||
| }) | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| import type { CustomIconName } from '@src/components/CustomIcon' | ||||
| import type { Project } from '@src/lib/project' | ||||
| import type { Prompt } from '@src/lib/prompt' | ||||
|  | ||||
| const DESC = ':desc' | ||||
|  | ||||
| @ -25,7 +26,7 @@ export function getNextSearchParams(currentSort: string, newSort: string) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| export function getSortFunction(sortBy: string) { | ||||
| export function getProjectSortFunction(sortBy: string) { | ||||
|   const sortByName = (a: Project, b: Project) => { | ||||
|     if (a.name && b.name) { | ||||
|       return sortBy.includes('desc') | ||||
| @ -52,3 +53,33 @@ export function getSortFunction(sortBy: string) { | ||||
|     return sortByModified | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Below is to keep the same behavior as above but for prompts. | ||||
| // Do NOT take it as actually "sort by modified" but more like "sort by time". | ||||
| export function getPromptSortFunction(sortBy: string) { | ||||
|   const sortByName = (a: Prompt, b: Prompt) => { | ||||
|     if (a.prompt && b.prompt) { | ||||
|       return sortBy.includes('desc') | ||||
|         ? a.prompt.localeCompare(b.prompt) | ||||
|         : b.prompt.localeCompare(a.prompt) | ||||
|     } | ||||
|     return 0 | ||||
|   } | ||||
|  | ||||
|   const sortByModified = (a: Prompt, b: Prompt) => { | ||||
|     if (a.created_at && b.created_at) { | ||||
|       const aDate = new Date(a.created_at) | ||||
|       const bDate = new Date(b.created_at) | ||||
|       return !sortBy || sortBy.includes('desc') | ||||
|         ? bDate.getTime() - aDate.getTime() | ||||
|         : aDate.getTime() - bDate.getTime() | ||||
|     } | ||||
|     return 0 | ||||
|   } | ||||
|  | ||||
|   if (sortBy?.includes('name')) { | ||||
|     return sortByName | ||||
|   } else { | ||||
|     return sortByModified | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,6 @@ | ||||
| import { setup, fromPromise } from 'xstate' | ||||
| import type { Prompt } from '@src/lib/prompt' | ||||
| import { generateFakeSubmittedPrompt } from '@src/lib/prompt' | ||||
|  | ||||
| export enum MlEphantManagerTransitionStates { | ||||
|   GetPromptsThatCreatedProjects = 'get-prompts-that-created-projects', | ||||
| @ -47,9 +49,9 @@ export enum MlEphantManagerStates { | ||||
| } | ||||
|  | ||||
| export interface MlEphantManagerContext { | ||||
|   promptsThatCreatedProjects: Map<Prompt> | ||||
|   promptsThatCreatedProjects: Map<Prompt['id'], Prompt> | ||||
|   // If no project is selected: undefined. | ||||
|   promptsBelongingToProject?: Map<Prompt> | ||||
|   promptsBelongingToProject?: Map<Prompt['id'], Prompt> | ||||
| } | ||||
|  | ||||
| export const mlEphantDefaultContext = Object.freeze({ | ||||
| @ -58,13 +60,25 @@ export const mlEphantDefaultContext = Object.freeze({ | ||||
|   hasPendingPrompts: false, | ||||
| }) | ||||
|  | ||||
| const machine = setup({ | ||||
| export const mlEphantManagerMachine = setup({ | ||||
|   types: { | ||||
|     context: {} as MlEphantManagerContext, | ||||
|     events: {} as MlEphantManagerEvents, | ||||
|   }, | ||||
|   actors: { | ||||
|     [MlEphantManagerTransitionStates.GetPromptsThatCreatedProjects]: | ||||
|       fromPromise(async function (args) { | ||||
|         console.log(arguments) | ||||
|         return { | ||||
|           promptsThatCreatedProjects: new Array(13) | ||||
|             .fill(undefined) | ||||
|             .map(generateFakeSubmittedPrompt), | ||||
|         } | ||||
|       }), | ||||
|   }, | ||||
| }).createMachine({ | ||||
|   initial: MlEphantManagerStates.Idle, | ||||
|   context: mlEphantDefaultContext, | ||||
|   states: { | ||||
|     [MlEphantManagerStates.Idle]: { | ||||
|       on: { | ||||
| @ -77,15 +91,8 @@ const machine = setup({ | ||||
|       states: { | ||||
|         [MlEphantManagerTransitionStates.GetPromptsThatCreatedProjects]: { | ||||
|           invoke: { | ||||
|             input: (args) => args, | ||||
|             src: fromPromise(async function (args) { | ||||
|               console.log(arguments) | ||||
|               return { | ||||
|                 promptsThatCreatedProjects: new Array(13) | ||||
|                   .fill(undefined) | ||||
|                   .map(generateFakeSubmittedPrompt), | ||||
|               } | ||||
|             }), | ||||
|             input: (args: any) => args, | ||||
|             src: MlEphantManagerTransitionStates.GetPromptsThatCreatedProjects, | ||||
|             onDone: { target: MlEphantManagerStates.Idle }, | ||||
|             onError: { target: MlEphantManagerStates.Idle }, | ||||
|           }, | ||||
|  | ||||
| @ -17,10 +17,10 @@ import { PromptCard } from '@src/components/PromptCard' | ||||
| import { | ||||
|   HomeSearchBar, | ||||
|   useHomeSearch, | ||||
|   HomeItems, | ||||
|   areHomeItemsProjects, | ||||
|   areHomeItemsPrompts, | ||||
| } from '@src/components/HomeSearchBar' | ||||
| import type { HomeItems } from '@src/components/HomeSearchBar' | ||||
| import { BillingDialog } from '@src/components/BillingDialog' | ||||
| import { useQueryParamEffects } from '@src/hooks/useQueryParamEffects' | ||||
| import { useMenuListener } from '@src/hooks/useMenu' | ||||
| @ -32,7 +32,8 @@ import type { Prompt } from '@src/lib/prompt' | ||||
| import { generateFakeSubmittedPrompt } from '@src/lib/prompt' | ||||
| import { | ||||
|   getNextSearchParams, | ||||
|   getSortFunction, | ||||
|   getProjectSortFunction, | ||||
|   getPromptSortFunction, | ||||
|   getSortIcon, | ||||
| } from '@src/lib/sorting' | ||||
| import { reportRejection } from '@src/lib/trap' | ||||
| @ -216,7 +217,7 @@ const Home = () => { | ||||
|     } | ||||
|   ) | ||||
|   const projects = useFolders() | ||||
|   const prompts = [ | ||||
|   const prompts: Prompt[] = [ | ||||
|     generateFakeSubmittedPrompt(), | ||||
|     generateFakeSubmittedPrompt(), | ||||
|     generateFakeSubmittedPrompt(), | ||||
| @ -228,7 +229,7 @@ const Home = () => { | ||||
|   const [tabSelected, setTabSelected] = useState<HomeTabKeys>( | ||||
|     HomeTabKeys.Projects | ||||
|   ) | ||||
|   const [items, setItems] = useState<Project[] | Prompt[]>(projects) | ||||
|   const [items, setItems] = useState<HomeItems>(projects) | ||||
|   const [searchParams, setSearchParams] = useSearchParams() | ||||
|   const { searchResults, query, searchAgainst } = useHomeSearch(projects) | ||||
|   const sortBy = searchParams.get('sort_by') ?? 'modified:desc' | ||||
| @ -484,6 +485,8 @@ function HomeTab(props: HomeTabProps) { | ||||
|         <div | ||||
|           className={el.key === selected ? cssActive : cssInactive} | ||||
|           onClick={onClickTab(el.key)} | ||||
|           role="tab" | ||||
|           tabIndex={0} | ||||
|         > | ||||
|           {el.name} | ||||
|         </div> | ||||
| @ -565,7 +568,7 @@ function HomeHeader({ | ||||
|                   : '', | ||||
|               }} | ||||
|             > | ||||
|               Last Modified | ||||
|               Age | ||||
|             </ActionButton> | ||||
|           </div> | ||||
|         </div> | ||||
| @ -653,18 +656,37 @@ function HomeItemsArea(props: HomeItemsAreaProps) { | ||||
|   ) | ||||
| } | ||||
|  | ||||
| interface ResultGridProjectsProps { | ||||
| interface ResultGridPromptsProps { | ||||
|   searchResults: Prompt[] | ||||
|   query: string | ||||
|   sortBy: string | ||||
| } | ||||
|  | ||||
| function ResultGridPrompts(props) { | ||||
| function ResultGridPrompts(props: ResultGridPromptsProps) { | ||||
|   // Maybe consider lifting this higher but I see no reason at the moment | ||||
|   const onAction = (...args: any) => { | ||||
|     console.log(args) | ||||
|   } | ||||
|   const onDelete = (...args: any) => { | ||||
|     console.log(args) | ||||
|   } | ||||
|   const onFeedback = (...args: any) => { | ||||
|     console.log(args) | ||||
|   } | ||||
|  | ||||
|   return ( | ||||
|     <div className="grid w-full sm:grid-cols-2 lg:grid-cols-2 xl:grid-cols-2 gap-4"> | ||||
|       {props.searchResults.map((prompt) => ( | ||||
|         <PromptCard key={prompt.id} {...prompt} /> | ||||
|       ))} | ||||
|       {props.searchResults | ||||
|         .sort(getPromptSortFunction(props.sortBy)) | ||||
|         .map((prompt: Prompt) => ( | ||||
|           <PromptCard | ||||
|             key={prompt.id} | ||||
|             {...prompt} | ||||
|             onAction={onAction} | ||||
|             onDelete={onDelete} | ||||
|             onFeedback={onFeedback} | ||||
|           /> | ||||
|         ))} | ||||
|     </div> | ||||
|   ) | ||||
| } | ||||
| @ -686,8 +708,8 @@ function ResultGridProjects(props: ResultGridProjectsProps) { | ||||
|         <> | ||||
|           {props.searchResults.length > 0 ? ( | ||||
|             <ul className="grid w-full sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4"> | ||||
|               {(props.searchResults ?? []) | ||||
|                 .sort(getSortFunction(props.sortBy)) | ||||
|               {props.searchResults | ||||
|                 .sort(getProjectSortFunction(props.sortBy)) | ||||
|                 .map((item) => ( | ||||
|                   <ProjectCard | ||||
|                     key={item.name} | ||||
| @ -700,9 +722,9 @@ function ResultGridProjects(props: ResultGridProjectsProps) { | ||||
|           ) : ( | ||||
|             <p className="p-4 my-8 border border-dashed rounded border-chalkboard-30 dark:border-chalkboard-70"> | ||||
|               No results found | ||||
|               {items.length === 0 | ||||
|               {props.searchResults.length === 0 | ||||
|                 ? ', ready to make your first one?' | ||||
|                 : ` with the search term "${query}"`} | ||||
|                 : ` with the search term "${props.query}"`} | ||||
|             </p> | ||||
|           )} | ||||
|         </> | ||||
|  | ||||
		Reference in New Issue
	
	Block a user