diff --git a/web/app/components/app/create-app-dialog/app-list/index.tsx b/web/app/components/app/create-app-dialog/app-list/index.tsx
index ac660cdb1fc..f8c0bcd6ada 100644
--- a/web/app/components/app/create-app-dialog/app-list/index.tsx
+++ b/web/app/components/app/create-app-dialog/app-list/index.tsx
@@ -222,7 +222,7 @@ const Apps = ({
{searchFilteredList.map(app => (
diff --git a/web/app/components/apps/__tests__/list.spec.tsx b/web/app/components/apps/__tests__/list.spec.tsx
index e2d8056ba7b..4e9fa240af9 100644
--- a/web/app/components/apps/__tests__/list.spec.tsx
+++ b/web/app/components/apps/__tests__/list.spec.tsx
@@ -429,17 +429,19 @@ describe('List', () => {
expect(screen.getByRole('button', { name: 'common.operation.create' }))!.toBeInTheDocument()
})
- it('should render sort filter before search and the snippets link', () => {
+ it('should render search before the right aligned actions', () => {
renderList()
- const sortButton = screen.getByRole('button', { name: 'Sort by Last modified' })
+ const creatorsButton = screen.getByRole('button', { name: 'Creators' })
const searchInput = screen.getByRole('searchbox', { name: 'app.gotoAnything.actions.searchApplications' })
+ const sortButton = screen.getByRole('button', { name: 'Sort by Last modified' })
const snippetsLink = screen.getByRole('link', { name: 'app.studio.viewSnippets' })
const createButton = screen.getByRole('button', { name: 'common.operation.create' })
expect(snippetsLink).toHaveAttribute('href', '/snippets')
- expect(sortButton.compareDocumentPosition(searchInput) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy()
- expect(searchInput.compareDocumentPosition(snippetsLink) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy()
+ expect(creatorsButton.compareDocumentPosition(searchInput) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy()
+ expect(searchInput.compareDocumentPosition(sortButton) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy()
+ expect(sortButton.compareDocumentPosition(snippetsLink) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy()
expect(snippetsLink.compareDocumentPosition(createButton) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy()
})
@@ -450,6 +452,17 @@ describe('List', () => {
expect(screen.getByTestId('app-card-app-2'))!.toBeInTheDocument()
})
+ it('should lay out app cards with auto-fill grid columns', () => {
+ renderList()
+
+ const grid = screen.getByTestId('app-card-app-1').parentElement
+
+ expect(grid).toHaveClass(
+ 'grid',
+ 'grid-cols-[repeat(auto-fill,minmax(296px,1fr))]',
+ )
+ })
+
it('should hide starred section when there are no starred apps', () => {
renderList()
@@ -522,6 +535,24 @@ describe('List', () => {
expect(screen.queryByTestId('empty-state')).not.toBeInTheDocument()
})
+ it('should lay out first empty state placeholder cards with auto-fill grid columns', () => {
+ mockAppData = { pages: [{ data: [], total: 0 }] }
+
+ const { container } = renderList()
+ const placeholderGrid = Array.from(container.querySelectorAll('.pointer-events-none'))
+ .find(element => element.className.includes('grid-rows-4'))
+
+ if (!placeholderGrid)
+ throw new Error('Expected first empty state placeholder grid to render')
+
+ expect(placeholderGrid).toHaveClass(
+ 'grid',
+ 'grid-cols-[repeat(auto-fill,minmax(296px,1fr))]',
+ 'grid-rows-4',
+ )
+ expect(placeholderGrid).not.toHaveClass('grid-cols-1', 'sm:grid-cols-2', 'lg:grid-cols-3', 'xl:grid-cols-4')
+ })
+
it('should hide learn dify in first empty state when learn app is disabled', () => {
mockAppData = { pages: [{ data: [], total: 0 }] }
diff --git a/web/app/components/apps/app-card.tsx b/web/app/components/apps/app-card.tsx
index 4242a7214ef..f22bc28e931 100644
--- a/web/app/components/apps/app-card.tsx
+++ b/web/app/components/apps/app-card.tsx
@@ -1058,11 +1058,20 @@ export function AppCard({ app, onlineUsers = [], onRefresh, onOpenTagManagement
-
+
-
{app.author_name}
-
·
-
{editTimeText}
+ {app.author_name && (
+ <>
+
{app.author_name}
+
·
+ >
+ )}
+
{editTimeText}
>
diff --git a/web/app/components/apps/app-list-header-filters.tsx b/web/app/components/apps/app-list-header-filters.tsx
index 04379fd5c1d..f31c1052ecc 100644
--- a/web/app/components/apps/app-list-header-filters.tsx
+++ b/web/app/components/apps/app-list-header-filters.tsx
@@ -54,8 +54,8 @@ export function AppListHeaderFilters({
const { t } = useTranslation()
return (
-
-
+
+
-
+
+
{t('studio.viewSnippets', { ns: 'app' })}
@@ -87,7 +88,7 @@ export function AppListHeaderFilters({