mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
feat(core): workspace attachment uploading & error (#12330)
### TL;DR feat: optimize workspace attachment uploading & error display  ### What Changes #### Support for Workspace Attachment Uploading & Error Handling * Added support for three attachment states: uploading (local), upload failed (local error), and uploaded (persisted). The frontend UI now displays real-time upload progress and error messages. * Attachments that fail to upload can be deleted directly without confirmation. * Merged display of uploading and uploaded attachments for a smoother user experience. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Attachments now show real-time upload status including uploading, error, and uploaded states. - Users can remove failed (error) attachments instantly without confirmation. - Attachment list merges uploading and uploaded files, displaying up to 10 items. - **Bug Fixes** - Improved error handling and messaging for failed attachment uploads. - **Style** - Enhanced visual styling for error attachments with distinct colors and backgrounds. - **Tests** - Added tests simulating slow network uploads, upload failures, and direct removal of error attachments. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -82,15 +82,42 @@ test.describe('AISettings/Embedding', () => {
|
||||
buffer: buffer2,
|
||||
},
|
||||
];
|
||||
|
||||
const client = await page.context().newCDPSession(page);
|
||||
await client.send('Network.enable');
|
||||
await client.send('Network.emulateNetworkConditions', {
|
||||
offline: false,
|
||||
latency: 1000,
|
||||
downloadThroughput: (50 * 1024) / 8,
|
||||
uploadThroughput: (50 * 1024) / 8,
|
||||
connectionType: 'cellular3g',
|
||||
});
|
||||
|
||||
await utils.settings.uploadWorkspaceEmbedding(page, attachments);
|
||||
|
||||
const attachmentList = await page.getByTestId(
|
||||
'workspace-embedding-setting-attachment-list'
|
||||
);
|
||||
|
||||
// Uploading
|
||||
await expect(
|
||||
attachmentList.getByTestId(
|
||||
'workspace-embedding-setting-attachment-uploading-item'
|
||||
)
|
||||
).toHaveCount(2);
|
||||
|
||||
// Persisted
|
||||
await expect(
|
||||
attachmentList.getByTestId('workspace-embedding-setting-attachment-item')
|
||||
).toHaveCount(2);
|
||||
|
||||
await client.send('Network.emulateNetworkConditions', {
|
||||
offline: false,
|
||||
latency: 0,
|
||||
downloadThroughput: -1,
|
||||
uploadThroughput: -1,
|
||||
});
|
||||
|
||||
await utils.settings.closeSettingsPanel(page);
|
||||
|
||||
await page.waitForTimeout(5000); // wait for the embedding to be ready
|
||||
@@ -120,6 +147,36 @@ test.describe('AISettings/Embedding', () => {
|
||||
}).toPass({ timeout: 20000 });
|
||||
});
|
||||
|
||||
test('should display failed info if upload attachment failed', async ({
|
||||
loggedInPage: page,
|
||||
utils,
|
||||
}) => {
|
||||
await utils.settings.enableWorkspaceEmbedding(page);
|
||||
const attachments = [
|
||||
{
|
||||
name: 'document1.txt',
|
||||
mimeType: 'text/plain',
|
||||
buffer: Buffer.from('HelloWorld'),
|
||||
},
|
||||
];
|
||||
|
||||
await page.context().setOffline(true);
|
||||
|
||||
await utils.settings.uploadWorkspaceEmbedding(page, attachments);
|
||||
|
||||
const attachmentList = await page.getByTestId(
|
||||
'workspace-embedding-setting-attachment-list'
|
||||
);
|
||||
|
||||
const errorItem = await attachmentList.getByTestId(
|
||||
'workspace-embedding-setting-attachment-error-item'
|
||||
);
|
||||
await errorItem.hover();
|
||||
await expect(page.getByText(/Network error/i)).toBeVisible();
|
||||
|
||||
await page.context().setOffline(false);
|
||||
});
|
||||
|
||||
test('should support hybrid search for both globally uploaded attachments and those uploaded in the current session', async ({
|
||||
loggedInPage: page,
|
||||
utils,
|
||||
@@ -216,7 +273,7 @@ test.describe('AISettings/Embedding', () => {
|
||||
).toHaveText('document1.txt');
|
||||
});
|
||||
|
||||
test('should support remove attachment', async ({
|
||||
test('should support remove attachment with confirm', async ({
|
||||
loggedInPage: page,
|
||||
utils,
|
||||
}) => {
|
||||
@@ -240,6 +297,25 @@ test.describe('AISettings/Embedding', () => {
|
||||
await utils.settings.removeAttachment(page, 'document1.txt');
|
||||
});
|
||||
|
||||
test('should support remove error attachment directly', async ({
|
||||
loggedInPage: page,
|
||||
utils,
|
||||
}) => {
|
||||
await utils.settings.enableWorkspaceEmbedding(page);
|
||||
const textContent = 'WorkspaceEBEEE is a cute cat';
|
||||
const attachments = [
|
||||
{
|
||||
name: 'document1.txt',
|
||||
mimeType: 'text/plain',
|
||||
buffer: Buffer.from(textContent),
|
||||
},
|
||||
];
|
||||
await page.context().setOffline(true);
|
||||
await utils.settings.uploadWorkspaceEmbedding(page, attachments);
|
||||
await utils.settings.removeAttachment(page, 'document1.txt', false);
|
||||
await page.context().setOffline(false);
|
||||
});
|
||||
|
||||
// FIXME: wait for indexer
|
||||
test.skip('should support ignore docs for embedding', async ({
|
||||
loggedInPage: page,
|
||||
|
||||
@@ -87,23 +87,35 @@ export class SettingsPanelUtils {
|
||||
|
||||
while (count > 0) {
|
||||
const attachmentItem = await page.getByTestId(itemId).first();
|
||||
const hasErrorItem = await attachmentItem
|
||||
.getByTestId('workspace-embedding-setting-attachment-error-item')
|
||||
.isVisible();
|
||||
await attachmentItem
|
||||
.getByTestId('workspace-embedding-setting-attachment-delete-button')
|
||||
.click();
|
||||
await page.getByTestId('confirm-modal-confirm').click();
|
||||
|
||||
if (!hasErrorItem) {
|
||||
await page.getByTestId('confirm-modal-confirm').click();
|
||||
}
|
||||
await page.waitForTimeout(1000);
|
||||
count = await page.getByTestId(itemId).count();
|
||||
}
|
||||
}
|
||||
|
||||
public static async removeAttachment(page: Page, attachment: string) {
|
||||
public static async removeAttachment(
|
||||
page: Page,
|
||||
attachment: string,
|
||||
shouldConfirm = true
|
||||
) {
|
||||
const attachmentItem = await page
|
||||
.getByTestId('workspace-embedding-setting-attachment-item')
|
||||
.filter({ hasText: attachment });
|
||||
await attachmentItem
|
||||
.getByTestId('workspace-embedding-setting-attachment-delete-button')
|
||||
.click();
|
||||
await page.getByTestId('confirm-modal-confirm').click();
|
||||
if (shouldConfirm) {
|
||||
await page.getByTestId('confirm-modal-confirm').click();
|
||||
}
|
||||
await page
|
||||
.getByTestId('workspace-embedding-setting-attachment-item')
|
||||
.filter({ hasText: attachment })
|
||||
|
||||
Reference in New Issue
Block a user