-
Notifications
You must be signed in to change notification settings - Fork 156
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5073 from owncloud/lazy-avatars
background loading for avatars
- Loading branch information
Showing
8 changed files
with
232 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
Enhancement: Lazy file avatar loading | ||
|
||
We've changed the way how large file lists get rendered. | ||
In some cases where we had a long list of files, the loading of avatars could lead to long waiting times till the first paint happens. | ||
|
||
Now we first render the list of files, load the associated avatars in the background and then update the ui. | ||
|
||
https://github.com/owncloud/web/pull/5073 | ||
https://github.com/owncloud/web/issues/4973 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,46 @@ | ||
export async function getAvatarSrc(userId, server, token) { | ||
const headers = new Headers() | ||
const url = server + 'remote.php/dav/avatars/' + userId + '/128.png' | ||
const urlCache = new Map() | ||
const ttl = 60 * 1000 | ||
const addUrl = (userId, url) => { | ||
urlCache.set(userId, { | ||
ts: Date.now() + ttl, | ||
url | ||
}) | ||
|
||
return url | ||
} | ||
const getUrl = userId => { | ||
if (urlCache.has(userId)) { | ||
const { ts, url } = urlCache.get(userId) | ||
if (Date.now() <= ts) { | ||
return url | ||
} | ||
} | ||
} | ||
|
||
export async function getAvatarSrc(userId, server, token, client) { | ||
const cachedUrl = getUrl(userId) | ||
|
||
if (cachedUrl) { | ||
return cachedUrl | ||
} | ||
|
||
const url = server + 'remote.php/dav/avatars/' + userId + '/128.png' | ||
const headers = new Headers() | ||
headers.append('Authorization', 'Bearer ' + token) | ||
|
||
const response = await fetch(url, { | ||
method: 'HEAD', | ||
headers | ||
}) | ||
|
||
if (response.status === 200) { | ||
return await this.$client.signUrl(url) | ||
if (response.status !== 200) { | ||
throw new Error(response.statusText) | ||
} | ||
|
||
if (!client || typeof client.signUrl !== 'function') { | ||
return addUrl(userId, url) | ||
} | ||
|
||
return '' | ||
const signedUrl = await client.signUrl(url) | ||
return addUrl(userId, signedUrl) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { buildSharedResource } from '../../src/helpers/resources' | ||
|
||
describe('buildSharedResource', () => { | ||
const resourceFactory = (incomingShares = false) => { | ||
let doResolve | ||
let pending = true | ||
let fulfilled = false | ||
|
||
const resourceUpdater = new Promise(resolve => (doResolve = resolve)) | ||
resourceUpdater.pending = () => pending | ||
resourceUpdater.fulfilled = () => fulfilled | ||
|
||
const resource = buildSharedResource( | ||
{ | ||
file_target: '/path.pdf', | ||
path: '/path.pdf', | ||
displayname_owner: 'displayname_owner', | ||
sharedWith: [ | ||
{ | ||
username: 'sharedWith', | ||
avatar: undefined | ||
} | ||
] | ||
}, | ||
incomingShares, | ||
'', | ||
'', | ||
'', | ||
'', | ||
r => { | ||
fulfilled = true | ||
pending = false | ||
doResolve(r) | ||
} | ||
) | ||
|
||
return { resource, resourceUpdater } | ||
} | ||
|
||
it('fetches avatars for outgoing shares in the background', async () => { | ||
const { resource, resourceUpdater } = resourceFactory() | ||
expect(resource.sharedWith[0].avatar).toBeFalsy() | ||
expect(resourceUpdater.pending()).toBeTruthy() | ||
expect(resourceUpdater.fulfilled()).toBeFalsy() | ||
|
||
const updatedResource = await resourceUpdater | ||
expect(updatedResource.sharedWith[0].avatar).toBeTruthy() | ||
expect(resourceUpdater.pending()).toBeFalsy() | ||
expect(resourceUpdater.fulfilled()).toBeTruthy() | ||
}) | ||
|
||
it('fetches avatars for incoming shares in the background', async () => { | ||
const { resource, resourceUpdater } = resourceFactory(true) | ||
expect(resource.owner[0].avatar).toBeFalsy() | ||
expect(resourceUpdater.pending()).toBeTruthy() | ||
expect(resourceUpdater.fulfilled()).toBeFalsy() | ||
|
||
const updatedResource = await resourceUpdater | ||
expect(updatedResource.owner[0].avatar).toBeTruthy() | ||
expect(resourceUpdater.pending()).toBeFalsy() | ||
expect(resourceUpdater.fulfilled()).toBeTruthy() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { getAvatarSrc } from '../../src/helpers/user' | ||
|
||
describe('getAvatarSrc', () => { | ||
it('throws an error', async () => { | ||
fetch.mockResponse(new Error(), { status: 404 }) | ||
await expect(getAvatarSrc('userId', 'server', 'token')).rejects.toBeTruthy() | ||
}) | ||
|
||
it('returns a signed url', async () => { | ||
fetch.mockResponse('', { status: 200 }) | ||
const client = { signUrl: jest.fn() } | ||
await getAvatarSrc('userId', 'server', 'token', client) | ||
expect(client.signUrl.mock.calls.length).toBe(1) | ||
}) | ||
|
||
it('returns the url if no valid client is present', async () => { | ||
fetch.mockResponse('', { status: 200 }) | ||
const url = await getAvatarSrc('userId', 'server', 'token') | ||
expect(url).toBe('serverremote.php/dav/avatars/userId/128.png') | ||
}) | ||
|
||
it('fetches avatarSrc from cache if url exists there', async () => { | ||
fetch.mockResponse('', { status: 200 }) | ||
const client = { signUrl: jest.fn() } | ||
await getAvatarSrc('userId', 'server', 'token', client) | ||
expect(client.signUrl.mock.calls.length).toBe(0) | ||
}) | ||
}) |