Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
search by owner in avatars table (#9073)
Browse files Browse the repository at this point in the history
* search by owner in avatars table

* feat: resolve user and sort user name on client

* chore: add comment for Type.Any

* fix: sort users by name in server
  • Loading branch information
aditya-mitra authored Oct 25, 2023
1 parent 8b4d14a commit 4d6ba78
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 57 deletions.
4 changes: 2 additions & 2 deletions packages/client-core/src/admin/common/variables/avatar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Ethereal Engine. All Rights Reserved.
import { AvatarType } from '@etherealengine/engine/src/schemas/user/avatar.schema'

export interface AvatarColumn {
id: 'select' | 'id' | 'name' | 'owner' | 'thumbnail' | 'action'
id: 'select' | 'id' | 'name' | 'user' | 'thumbnail' | 'action'
label: string | React.ReactElement
minWidth?: number
align?: 'right'
Expand All @@ -35,7 +35,7 @@ export interface AvatarColumn {
export const avatarColumns: AvatarColumn[] = [
{ id: 'id', label: 'Id', minWidth: 65 },
{ id: 'name', label: 'Name', minWidth: 65 },
{ id: 'owner', label: 'Owner', minWidth: 65 },
{ id: 'user', label: 'Owner', minWidth: 65 },
{
id: 'thumbnail',
label: 'Thumbnail',
Expand Down
98 changes: 48 additions & 50 deletions packages/client-core/src/admin/components/Avatars/AvatarTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import Checkbox from '@etherealengine/ui/src/primitives/mui/Checkbox'

import { useFind, useMutation } from '@etherealengine/engine/src/common/functions/FeathersHooks'
import TableComponent from '../../common/Table'
import { AvatarColumn, AvatarData, avatarColumns } from '../../common/variables/avatar'
import { AvatarColumn, avatarColumns } from '../../common/variables/avatar'
import styles from '../../styles/admin.module.scss'
import AvatarDrawer, { AvatarDrawerMode } from './AvatarDrawer'

Expand Down Expand Up @@ -83,56 +83,54 @@ const AvatarTable = ({ className, search, selectedAvatarIds, setSelectedAvatarId
}
}

const createData = (el: AvatarType): AvatarData => {
return {
el,
select: (
<>
<Checkbox
className={styles.checkbox}
checked={selectedAvatarIds.has(el.id)}
onChange={() => {
toggleSelection(el.id)
}}
/>
</>
),
id: el.id,
name: el.name as string,
owner: el.userId,
thumbnail: (
<img
style={{ maxHeight: '50px' }}
crossOrigin="anonymous"
src={el.thumbnailResource?.url + '?' + new Date().getTime()}
alt=""
const createData = (el: AvatarType): any => ({
el,
select: (
<>
<Checkbox
className={styles.checkbox}
checked={selectedAvatarIds.has(el.id)}
onChange={() => {
toggleSelection(el.id)
}}
/>
),
action: (
<>
<a
className={styles.actionStyle}
onClick={() => {
avatarData.set(el)
openAvatarDrawer.set(true)
}}
>
<span className={styles.spanWhite}>{t('admin:components.common.view')}</span>
</a>
<a
className={styles.actionStyle}
onClick={() => {
avatarId.set(el.id)
avatarName.set(el.name)
openConfirm.set(true)
}}
>
<span className={styles.spanDange}>{t('admin:components.common.delete')}</span>
</a>
</>
)
}
}
</>
),
id: el.id,
name: el.name as string,
user: el.user?.name || '',
thumbnail: (
<img
style={{ maxHeight: '50px' }}
crossOrigin="anonymous"
src={el.thumbnailResource?.url + '?' + new Date().getTime()}
alt=""
/>
),
action: (
<>
<a
className={styles.actionStyle}
onClick={() => {
avatarData.set(el)
openAvatarDrawer.set(true)
}}
>
<span className={styles.spanWhite}>{t('admin:components.common.view')}</span>
</a>
<a
className={styles.actionStyle}
onClick={() => {
avatarId.set(el.id)
avatarName.set(el.name)
openConfirm.set(true)
}}
>
<span className={styles.spanDange}>{t('admin:components.common.delete')}</span>
</a>
</>
)
})

const submitRemoveAvatar = async () => {
adminAvatarRemove(avatarId.value)
Expand Down
3 changes: 2 additions & 1 deletion packages/engine/src/schemas/user/avatar.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const avatarSchema = Type.Object(
format: 'uuid'
}),
project: Type.String(),
user: Type.Optional(Type.Any()), // avoid circular reference to `userSchema` which utilizes current `avatarSchema`
modelResource: Type.Optional(Type.Ref(staticResourceSchema)),
thumbnailResource: Type.Optional(Type.Ref(staticResourceSchema)),
createdAt: Type.String({ format: 'date-time' }),
Expand All @@ -64,7 +65,7 @@ export const avatarSchema = Type.Object(
)
export type AvatarType = Static<typeof avatarSchema>

export type AvatarDatabaseType = Omit<AvatarType, 'modelResource' | 'thumbnailResource'>
export type AvatarDatabaseType = Omit<AvatarType, 'user' | 'modelResource' | 'thumbnailResource'>

// Schema for creating new entries
// export const avatarDataSchema = Type.Pick(
Expand Down
24 changes: 20 additions & 4 deletions packages/server-core/src/user/avatar/avatar.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,25 @@ const ensureUserAccessibleAvatars = async (context: HookContext<AvatarService>)
isPublic: true
}
}
}

const sortByUserName = async (context: HookContext<AvatarService>) => {
if (!context.params.query || !context.params.query.$sort?.['user']) return

const userSort = context.params.query.$sort['user']
delete context.params.query.$sort['user']

if (context.params.query.name) {
context.params.query[`${avatarPath}.name`] = context.params.query.name
delete context.params.query.name
}

const query = context.service.createQuery(context.params)

return context
query.leftJoin(userPath, `${userPath}.id`, `${avatarPath}.userId`)
query.orderBy(`${userPath}.name`, userSort === 1 ? 'asc' : 'desc')

context.params.knex = query
}

/**
Expand All @@ -119,8 +136,6 @@ const removeAvatarResources = async (context: HookContext<AvatarService>) => {
} catch (err) {
logger.error(err)
}

return context
}

/**
Expand Down Expand Up @@ -164,7 +179,8 @@ export default {
all: [() => schemaHooks.validateQuery(avatarQueryValidator), schemaHooks.resolveQuery(avatarQueryResolver)],
find: [
iffElse(isAction('admin'), verifyScope('admin', 'admin'), ensureUserAccessibleAvatars),
discardQuery('action')
discardQuery('action'),
sortByUserName
],
get: [],
create: [
Expand Down
6 changes: 6 additions & 0 deletions packages/server-core/src/user/avatar/avatar.resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { staticResourcePath } from '@etherealengine/engine/src/schemas/media/sta
import { AvatarDatabaseType, AvatarQuery, AvatarType } from '@etherealengine/engine/src/schemas/user/avatar.schema'
import type { HookContext } from '@etherealengine/server-core/declarations'

import { userPath } from '@etherealengine/engine/src/schemas/user/user.schema'
import { fromDateTimeSql, getDateTimeSql } from '../../util/datetime-sql'

export const avatarResolver = resolve<AvatarType, HookContext>({
Expand All @@ -39,6 +40,11 @@ export const avatarResolver = resolve<AvatarType, HookContext>({
})

export const avatarExternalResolver = resolve<AvatarType, HookContext>({
user: virtual(async (avatar, context) => {
if (avatar.userId) {
return context.app.service(userPath).get(avatar.userId)
}
}),
modelResource: virtual(async (avatar, context) => {
if (context.event !== 'removed' && avatar.modelResourceId)
return context.app.service(staticResourcePath).get(avatar.modelResourceId)
Expand Down

0 comments on commit 4d6ba78

Please sign in to comment.