'use client' import type { KeyboardEvent } from 'react' import type { App } from '@/types/app' import { cn } from '@langgenius/dify-ui/cn' import { toast } from '@langgenius/dify-ui/toast' import { useSuspenseQuery } from '@tanstack/react-query' import { useAtomValue } from 'jotai' import { useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' import { AppTypeIcon } from '@/app/components/app/type-selector' import AppIcon from '@/app/components/base/app-icon' import { userProfileIdAtom } from '@/context/account-state' import { workspacePermissionKeysAtom } from '@/context/permission-state' import { systemFeaturesQueryOptions } from '@/features/system-features/client' import Link from '@/next/link' import { getRedirectionPath } from '@/utils/app-redirection' import { hasOnlyAppPreviewPermission } from '@/utils/permission' import { formatTime } from '@/utils/time' import { AppCardActionBar } from './app-card' type StarredAppCardProps = { app: App onRefresh?: () => void stepByStepTourCardTarget?: string stepByStepTourCardHighlightPart?: string } export function StarredAppCard({ app, onRefresh, stepByStepTourCardTarget, stepByStepTourCardHighlightPart, }: StarredAppCardProps) { const { t } = useTranslation() const currentUserId = useAtomValue(userProfileIdAtom) const workspacePermissionKeys = useAtomValue(workspacePermissionKeysAtom) const { data: systemFeatures } = useSuspenseQuery(systemFeaturesQueryOptions()) const isRbacEnabled = systemFeatures.rbac_enabled const isPreviewOnly = hasOnlyAppPreviewPermission(app.permission_keys) const editTimeText = useMemo(() => { const timestamp = app.updated_at || app.created_at if (!timestamp) return '' const timeText = formatTime({ date: timestamp * 1000, dateFormat: `${t(($) => $['segment.dateTimeFormat'], { ns: 'datasetDocuments' })}`, }) return `${t(($) => $['segment.editedAt'], { ns: 'datasetDocuments' })} ${timeText}` }, [app.created_at, app.updated_at, t]) const href = getRedirectionPath(app, { currentUserId, resourceMaintainer: app.maintainer, workspacePermissionKeys, isRbacEnabled, }) const cardClassName = cn( 'flex h-[72px] min-w-0 items-center gap-3 overflow-hidden rounded-xl border-[0.5px] border-components-card-border bg-components-card-bg px-4 py-3 shadow-xs outline-hidden transition-shadow duration-200', isPreviewOnly ? 'cursor-not-allowed opacity-60 focus-visible:ring-2 focus-visible:ring-state-accent-solid' : 'hover:shadow-lg focus-visible:ring-2 focus-visible:ring-state-accent-solid', ) const showPreviewOnlyAccessWarning = useCallback(() => { toast.warning(t(($) => $.noAccessResourcePermission, { ns: 'app' })) }, [t]) const handlePreviewOnlyCardKeyDown = useCallback( (event: KeyboardEvent) => { if (event.key !== 'Enter' && event.key !== ' ') return event.preventDefault() showPreviewOnlyAccessWarning() }, [showPreviewOnlyAccessWarning], ) const cardContent = ( <>
{app.name}
{app.author_name && {app.author_name}} {app.author_name && editTimeText && ยท} {editTimeText && {editTimeText}}
) return (
{isPreviewOnly ? (
{cardContent}
) : ( {cardContent} )} {!isPreviewOnly && }
) }