admin(ui): display dynamic user information on sidebar
This commit is contained in:
parent
9eed88b430
commit
2352ef0369
|
@ -25,9 +25,11 @@ class VersionController extends ApplicationApiController
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ?
|
* Returns version information.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function __invoke()
|
public function __invoke(): JsonResponse
|
||||||
{
|
{
|
||||||
return new JsonResponse($this->softwareVersionService->getVersionData());
|
return new JsonResponse($this->softwareVersionService->getVersionData());
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,9 +168,13 @@ class User extends Model implements
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function toVueObject(): array
|
public function toReactObject(): array
|
||||||
{
|
{
|
||||||
return (new Collection($this->toArray()))->except(['id', 'external_id'])->toArray();
|
$object = (new Collection($this->toArray()))->except(['id', 'external_id'])->toArray();
|
||||||
|
$object['avatar_url'] = $this->avatarURL();
|
||||||
|
$object['role_name'] = $this->roleName();
|
||||||
|
|
||||||
|
return $object;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -203,6 +207,26 @@ class User extends Model implements
|
||||||
return trim($this->name_first . ' ' . $this->name_last);
|
return trim($this->name_first . ' ' . $this->name_last);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get's the avatar url for the user.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function avatarURL(): string
|
||||||
|
{
|
||||||
|
return 'https://www.gravatar.com/avatar/' . md5($this->email) . '.jpg';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get's the name of the role assigned to a user.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function roleName():? string
|
||||||
|
{
|
||||||
|
return $this->root_admin ? 'Super Administrator' : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all servers that a user owns.
|
* Returns all servers that a user owns.
|
||||||
*
|
*
|
||||||
|
|
|
@ -20,12 +20,12 @@ abstract class BaseTransformer extends TransformerAbstract
|
||||||
/**
|
/**
|
||||||
* @var \Pterodactyl\Models\ApiKey
|
* @var \Pterodactyl\Models\ApiKey
|
||||||
*/
|
*/
|
||||||
private $key;
|
private ApiKey $key;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private $rootAdmin;
|
private bool $rootAdmin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the resource name for the JSONAPI output.
|
* Return the resource name for the JSONAPI output.
|
||||||
|
|
|
@ -43,11 +43,10 @@ class UserTransformer extends BaseTransformer
|
||||||
'language' => $model->language,
|
'language' => $model->language,
|
||||||
'root_admin' => (bool) $model->root_admin,
|
'root_admin' => (bool) $model->root_admin,
|
||||||
'2fa' => (bool) $model->use_totp,
|
'2fa' => (bool) $model->use_totp,
|
||||||
'avatar_url' => 'https://www.gravatar.com/avatar/' . md5($model->email) . '.jpg?s=40',
|
'avatar_url' => $model->avatarURL(),
|
||||||
'role_name' => $model->root_admin ? 'Super Administrator' : null,
|
'role_name' => $model->roleName(),
|
||||||
'created_at' => $this->formatTimestamp($model->created_at),
|
'created_at' => $this->formatTimestamp($model->created_at),
|
||||||
'updated_at' => $this->formatTimestamp($model->updated_at),
|
'updated_at' => $this->formatTimestamp($model->updated_at),
|
||||||
'avatar'
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,13 @@ interface ExtendedWindow extends Window {
|
||||||
username: string;
|
username: string;
|
||||||
email: string;
|
email: string;
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
|
name_first: string;
|
||||||
|
name_last: string;
|
||||||
root_admin: boolean;
|
root_admin: boolean;
|
||||||
use_totp: boolean;
|
use_totp: boolean;
|
||||||
language: string;
|
language: string;
|
||||||
|
avatar_url: string;
|
||||||
|
role_name: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
/* eslint-enable camelcase */
|
/* eslint-enable camelcase */
|
||||||
|
@ -52,9 +56,13 @@ const App = () => {
|
||||||
uuid: PterodactylUser.uuid,
|
uuid: PterodactylUser.uuid,
|
||||||
username: PterodactylUser.username,
|
username: PterodactylUser.username,
|
||||||
email: PterodactylUser.email,
|
email: PterodactylUser.email,
|
||||||
|
firstName: PterodactylUser.name_first,
|
||||||
|
lastName: PterodactylUser.name_last,
|
||||||
language: PterodactylUser.language,
|
language: PterodactylUser.language,
|
||||||
rootAdmin: PterodactylUser.root_admin,
|
rootAdmin: PterodactylUser.root_admin,
|
||||||
useTotp: PterodactylUser.use_totp,
|
useTotp: PterodactylUser.use_totp,
|
||||||
|
avatarURL: PterodactylUser.avatar_url,
|
||||||
|
roleName: PterodactylUser.role_name,
|
||||||
createdAt: new Date(PterodactylUser.created_at),
|
createdAt: new Date(PterodactylUser.created_at),
|
||||||
updatedAt: new Date(PterodactylUser.updated_at),
|
updatedAt: new Date(PterodactylUser.updated_at),
|
||||||
});
|
});
|
||||||
|
|
|
@ -117,7 +117,7 @@ const UsersContainer = () => {
|
||||||
<NavLink to={`${match.url}/${user.id}`}>
|
<NavLink to={`${match.url}/${user.id}`}>
|
||||||
<div css={tw`flex items-center`}>
|
<div css={tw`flex items-center`}>
|
||||||
<div css={tw`flex-shrink-0 h-10 w-10`}>
|
<div css={tw`flex-shrink-0 h-10 w-10`}>
|
||||||
<img css={tw`h-10 w-10 rounded-full`} alt="" src={user.avatarURL}/>
|
<img css={tw`h-10 w-10 rounded-full`} alt="" src={user.avatarURL + '?s=40'}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div css={tw`ml-4`}>
|
<div css={tw`ml-4`}>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { NavLink, Route, RouteComponentProps, Switch } from 'react-router-dom';
|
import { NavLink, Route, RouteComponentProps, Switch } from 'react-router-dom';
|
||||||
import { useStoreState } from 'easy-peasy';
|
import { State, useStoreState } from 'easy-peasy';
|
||||||
import tw from 'twin.macro';
|
import tw from 'twin.macro';
|
||||||
import styled from 'styled-components/macro';
|
import styled from 'styled-components/macro';
|
||||||
import { ApplicationStore } from '@/state';
|
import { ApplicationStore } from '@/state';
|
||||||
|
@ -88,7 +88,9 @@ const Sidebar = styled.div<{ collapsed?: boolean }>`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AdminRouter = ({ location, match }: RouteComponentProps) => {
|
const AdminRouter = ({ location, match }: RouteComponentProps) => {
|
||||||
const name = useStoreState((state: ApplicationStore) => state.settings.data!.name);
|
const user = useStoreState((state: State<ApplicationStore>) => state.user.data);
|
||||||
|
const applicationName = useStoreState((state: ApplicationStore) => state.settings.data!.name);
|
||||||
|
|
||||||
const [ collapsed, setCollapsed ] = useState<boolean>();
|
const [ collapsed, setCollapsed ] = useState<boolean>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -96,7 +98,7 @@ const AdminRouter = ({ location, match }: RouteComponentProps) => {
|
||||||
<Sidebar collapsed={collapsed}>
|
<Sidebar collapsed={collapsed}>
|
||||||
<div className={'header'} onClick={ () => { setCollapsed(!collapsed); } }>
|
<div className={'header'} onClick={ () => { setCollapsed(!collapsed); } }>
|
||||||
{ !collapsed ?
|
{ !collapsed ?
|
||||||
<h1 css={tw`text-2xl text-neutral-50 whitespace-nowrap`}>{name}</h1>
|
<h1 css={tw`text-2xl text-neutral-50 whitespace-nowrap`}>{applicationName}</h1>
|
||||||
:
|
:
|
||||||
<img src={'/favicons/android-icon-48x48.png'} alt={'Pterodactyl Icon'} />
|
<img src={'/favicons/android-icon-48x48.png'} alt={'Pterodactyl Icon'} />
|
||||||
}
|
}
|
||||||
|
@ -162,11 +164,11 @@ const AdminRouter = ({ location, match }: RouteComponentProps) => {
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
|
||||||
<div className={'user'}>
|
<div className={'user'}>
|
||||||
<img src={'https://www.gravatar.com/avatar/78a6a270ec41715a8ae96c02b8961f9e?s=64'} alt="Profile Picture" css={tw`h-10 w-10 rounded-full select-none`} />
|
<img src={user !== undefined ? user.avatarURL + '?s=64' : ''} alt="Profile Picture" css={tw`h-10 w-10 rounded-full select-none`} />
|
||||||
|
|
||||||
<div css={tw`flex flex-col ml-4`}>
|
<div css={tw`flex flex-col ml-4`}>
|
||||||
<span css={tw`font-header font-medium text-sm text-neutral-50 whitespace-nowrap leading-tight select-none`}>Matthew Penner</span>
|
<span css={tw`font-header font-medium text-sm text-neutral-50 whitespace-nowrap leading-tight select-none`}>{user?.firstName} {user?.lastName}</span>
|
||||||
<span css={tw`font-header font-normal text-xs text-neutral-300 whitespace-nowrap leading-tight select-none`}>Super Administrator</span>
|
<span css={tw`font-header font-normal text-xs text-neutral-300 whitespace-nowrap leading-tight select-none`}>{user?.roleName}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<NavLink to={'/auth/logout'} css={tw`h-8 w-8 flex items-center justify-center text-neutral-300 hover:text-red-400 hover:bg-neutral-800 rounded ml-auto transition-all duration-100`}>
|
<NavLink to={'/auth/logout'} css={tw`h-8 w-8 flex items-center justify-center text-neutral-300 hover:text-red-400 hover:bg-neutral-800 rounded ml-auto transition-all duration-100`}>
|
||||||
|
|
|
@ -5,9 +5,13 @@ export interface UserData {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
username: string;
|
username: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
language: string;
|
language: string;
|
||||||
rootAdmin: boolean;
|
rootAdmin: boolean;
|
||||||
useTotp: boolean;
|
useTotp: boolean;
|
||||||
|
avatarURL: string;
|
||||||
|
roleName: string;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +25,7 @@ export interface UserStore {
|
||||||
|
|
||||||
const user: UserStore = {
|
const user: UserStore = {
|
||||||
data: undefined,
|
data: undefined,
|
||||||
|
|
||||||
setUserData: action((state, payload) => {
|
setUserData: action((state, payload) => {
|
||||||
state.data = payload;
|
state.data = payload;
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
@section('user-data')
|
@section('user-data')
|
||||||
@if(!is_null(Auth::user()))
|
@if(!is_null(Auth::user()))
|
||||||
<script>
|
<script>
|
||||||
window.PterodactylUser = {!! json_encode(Auth::user()->toVueObject()) !!};
|
window.PterodactylUser = {!! json_encode(Auth::user()->toReactObject()) !!};
|
||||||
</script>
|
</script>
|
||||||
@endif
|
@endif
|
||||||
@if(!empty($siteConfiguration))
|
@if(!empty($siteConfiguration))
|
||||||
|
|
Loading…
Reference in New Issue