diff --git a/invokeai/frontend/web/package.json b/invokeai/frontend/web/package.json index 329c0ec355..5d82dc3424 100644 --- a/invokeai/frontend/web/package.json +++ b/invokeai/frontend/web/package.json @@ -66,6 +66,7 @@ "chakra-react-select": "^4.9.2", "cmdk": "^1.0.0", "compare-versions": "^6.1.1", + "dateformat": "^5.0.3", "fracturedjsonjs": "^4.0.2", "framer-motion": "^11.10.0", "i18next": "^23.15.1", @@ -127,6 +128,7 @@ "@storybook/react": "^8.3.4", "@storybook/react-vite": "^8.3.4", "@storybook/theming": "^8.3.4", + "@types/dateformat": "^5.0.2", "@types/lodash-es": "^4.17.12", "@types/node": "^20.16.10", "@types/react": "^18.3.11", diff --git a/invokeai/frontend/web/pnpm-lock.yaml b/invokeai/frontend/web/pnpm-lock.yaml index e5ad9e9d07..4de3d05578 100644 --- a/invokeai/frontend/web/pnpm-lock.yaml +++ b/invokeai/frontend/web/pnpm-lock.yaml @@ -47,6 +47,9 @@ dependencies: compare-versions: specifier: ^6.1.1 version: 6.1.1 + dateformat: + specifier: ^5.0.3 + version: 5.0.3 fracturedjsonjs: specifier: ^4.0.2 version: 4.0.2 @@ -211,6 +214,9 @@ devDependencies: '@storybook/theming': specifier: ^8.3.4 version: 8.3.4(storybook@8.3.4) + '@types/dateformat': + specifier: ^5.0.2 + version: 5.0.2 '@types/lodash-es': specifier: ^4.17.12 version: 4.17.12 @@ -3407,6 +3413,10 @@ packages: '@types/d3-zoom': 3.0.8 dev: false + /@types/dateformat@5.0.2: + resolution: {integrity: sha512-M95hNBMa/hnwErH+a+VOD/sYgTmo15OTYTM2Hr52/e0OdOuY+Crag+kd3/ioZrhg0WGbl9Sm3hR7UU+MH6rfOw==} + dev: true + /@types/diff-match-patch@1.0.36: resolution: {integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==} dev: false @@ -4832,6 +4842,11 @@ packages: '@babel/runtime': 7.25.7 dev: true + /dateformat@5.0.3: + resolution: {integrity: sha512-Kvr6HmPXUMerlLcLF+Pwq3K7apHpYmGDVqrxcDasBg86UcKeTSNWbEzU8bwdXnxnR44FtMhJAxI4Bov6Y/KUfA==} + engines: {node: '>=12.20'} + dev: false + /de-indent@1.0.2: resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} dev: true diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListItem.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListItem.tsx index a1744fc0ab..fa03ddf986 100644 --- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListItem.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListItem.tsx @@ -10,6 +10,7 @@ import { } from '@invoke-ai/ui-library'; import { EMPTY_OBJECT } from 'app/store/constants'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import dateFormat, { masks } from 'dateformat'; import { $isWorkflowListMenuIsOpen } from 'features/nodes/store/workflowListMenu'; import { selectWorkflowId, workflowModeChanged } from 'features/nodes/store/workflowSlice'; import { useDeleteLibraryWorkflow } from 'features/workflowLibrary/hooks/useDeleteLibraryWorkflow'; @@ -21,6 +22,8 @@ import { useTranslation } from 'react-i18next'; import { PiDownloadSimpleBold, PiPencilBold, PiTrashBold } from 'react-icons/pi'; import type { WorkflowRecordListItemDTO } from 'services/api/types'; +import { WorkflowListItemTooltip } from './WorkflowListItemTooltip'; + export const WorkflowListItem = ({ workflow }: { workflow: WorkflowRecordListItemDTO }) => { const { isOpen, onOpen, onClose } = useDisclosure(); const { t } = useTranslation(); @@ -87,14 +90,31 @@ export const WorkflowListItem = ({ workflow }: { workflow: WorkflowRecordListIte onMouseOut={handleMouseOut} alignItems="center" > - - {workflow.name} + }> + + + {workflow.name} + + {isActive && ( + + {t('workflows.opened')} + + )} + + {workflow.category !== 'default' && ( + + {t('common.updated')}: {dateFormat(workflow.updated_at, masks.shortDate)}{' '} + {dateFormat(workflow.updated_at, masks.shortTime)} + + )} + - {isActive && ( - - {t('workflows.opened')} - - )} diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListItemTooltip.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListItemTooltip.tsx new file mode 100644 index 0000000000..5b2fb75240 --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListItemTooltip.tsx @@ -0,0 +1,26 @@ +import { Flex, Text } from '@invoke-ai/ui-library'; +import dateFormat, { masks } from 'dateformat'; +import { useTranslation } from 'react-i18next'; +import type { WorkflowRecordListItemDTO } from 'services/api/types'; + +export const WorkflowListItemTooltip = ({ workflow }: { workflow: WorkflowRecordListItemDTO }) => { + const { t } = useTranslation(); + return ( + + {workflow.description} + {workflow.category !== 'default' && ( + + + {t('workflows.opened')}: {dateFormat(workflow.opened_at, masks.shortDate)} + + + {t('common.updated')}: {dateFormat(workflow.updated_at, masks.shortDate)} + + + {t('common.created')}: {dateFormat(workflow.created_at, masks.shortDate)} + + + )} + + ); +}; diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListMenu.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListMenu.tsx index 94126b33f4..863750faae 100644 --- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListMenu.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/WorkflowListMenu/WorkflowListMenu.tsx @@ -1,6 +1,7 @@ import { Flex, Spinner } from '@invoke-ai/ui-library'; import { useStore } from '@nanostores/react'; import { EMPTY_ARRAY } from 'app/store/constants'; +import { $projectId } from 'app/store/nanostores/projectId'; import { $workflowCategories } from 'app/store/nanostores/workflowCategories'; import { useAppSelector } from 'app/store/storeHooks'; import { selectWorkflowSearchTerm } from 'features/nodes/store/workflowSlice'; @@ -14,8 +15,9 @@ import WorkflowSearch from './WorkflowSearch'; export const WorkflowListMenu = () => { const searchTerm = useAppSelector(selectWorkflowSearchTerm); + const projectId = useStore($projectId); const { data, isLoading } = useListWorkflowsQuery( - {}, + { order_by: projectId ? 'created_at' : 'opened_at' }, { selectFromResult: ({ data, isLoading }) => { const filteredData =