tmp
This commit is contained in:
parent
df6f5c3a09
commit
e7aeeace26
18 changed files with 614 additions and 65 deletions
75
app/Http/Controllers/Admin/RolesController.php
Normal file
75
app/Http/Controllers/Admin/RolesController.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Http\Requests\Admin\RoleFormRequest;
|
||||
use Pterodactyl\Repositories\Eloquent\AdminRolesRepository;
|
||||
|
||||
class RolesController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\AdminRolesRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* RolesController constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Repositories\Eloquent\AdminRolesRepository $repository
|
||||
*/
|
||||
public function __construct(AdminRolesRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all roles.
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return new JsonResponse($this->repository->all());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new role.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Admin\RoleFormRequest $request
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
*/
|
||||
public function create(RoleFormRequest $request)
|
||||
{
|
||||
$role = $this->repository->create($request->normalize());
|
||||
|
||||
return new JsonResponse($role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a role.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
|
||||
*/
|
||||
public function update()
|
||||
{
|
||||
return response('', 204);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a role.
|
||||
*
|
||||
* @param int $role_id
|
||||
*
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
|
||||
*/
|
||||
public function delete(int $role_id)
|
||||
{
|
||||
$this->repository->delete($role_id);
|
||||
|
||||
return response('', 204);
|
||||
}
|
||||
}
|
29
app/Http/Requests/Admin/RoleFormRequest.php
Normal file
29
app/Http/Requests/Admin/RoleFormRequest.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Admin;
|
||||
|
||||
use Pterodactyl\Models\AdminRole;
|
||||
|
||||
class RoleFormRequest extends AdminFormRequest
|
||||
{
|
||||
/**
|
||||
* Setup the validation rules to use for these requests.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
if ($this->method() === 'PATCH') {
|
||||
return AdminRole::getRulesForUpdate($this->route()->parameter('mount')->id);
|
||||
}
|
||||
|
||||
return AdminRole::getRules();
|
||||
}
|
||||
}
|
43
app/Models/AdminRole.php
Normal file
43
app/Models/AdminRole.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property string|null $description
|
||||
* @property int $sort_id
|
||||
*/
|
||||
class AdminRole extends Model
|
||||
{
|
||||
/**
|
||||
* The resource name for this model when it is transformed into an
|
||||
* API representation using fractal.
|
||||
*/
|
||||
const RESOURCE_NAME = 'admin_role';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'admin_roles';
|
||||
|
||||
/**
|
||||
* Fields that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'description',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public static $validationRules = [
|
||||
'name' => 'required|string|max:64',
|
||||
'description' => 'nullable|string|max:255',
|
||||
];
|
||||
}
|
18
app/Repositories/Eloquent/AdminRolesRepository.php
Normal file
18
app/Repositories/Eloquent/AdminRolesRepository.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Repositories\Eloquent;
|
||||
|
||||
use Pterodactyl\Models\AdminRole;
|
||||
|
||||
class AdminRolesRepository extends EloquentRepository
|
||||
{
|
||||
/**
|
||||
* Return the model backing this repository.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return AdminRole::class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateAdminRolesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('admin_roles', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name', 64);
|
||||
$table->string('description', 255)->nullable();
|
||||
$table->integer('sort_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('admin_roles');
|
||||
}
|
||||
}
|
15
resources/scripts/api/admin/roles/getRoles.ts
Normal file
15
resources/scripts/api/admin/roles/getRoles.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import http from '@/api/http';
|
||||
|
||||
export interface Role {
|
||||
id: number,
|
||||
name: string,
|
||||
description: string|null,
|
||||
}
|
||||
|
||||
export default (): Promise<Role[]> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get('/admin/roles')
|
||||
.then(({ data }) => resolve(data || []))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
|
@ -1,12 +1,22 @@
|
|||
import React, { useState } from 'react';
|
||||
import NewApiKeyButton from '@/components/admin/api/NewApiKeyButton';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import tw from 'twin.macro';
|
||||
import AdminContentBlock from '@/components/admin/AdminContentBlock';
|
||||
import Button from '@/components/elements/Button';
|
||||
import Spinner from '@/components/elements/Spinner';
|
||||
|
||||
interface Key {
|
||||
id: number,
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const [ loading ] = useState<boolean>(false);
|
||||
const [ keys ] = useState<any[]>([]);
|
||||
const [ loading, setLoading ] = useState<boolean>(true);
|
||||
const [ keys ] = useState<Key[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
setLoading(false);
|
||||
}, 500);
|
||||
});
|
||||
|
||||
return (
|
||||
<AdminContentBlock>
|
||||
|
@ -16,16 +26,14 @@ export default () => {
|
|||
<p css={tw`text-base text-neutral-400`}>Control access credentials for managing this Panel via the API.</p>
|
||||
</div>
|
||||
|
||||
<Button type={'button'} size={'large'} css={tw`h-10 ml-auto px-4 py-0`}>
|
||||
New API Key
|
||||
</Button>
|
||||
<NewApiKeyButton />
|
||||
</div>
|
||||
|
||||
<div css={tw`w-full flex flex-col`}>
|
||||
<div css={tw`w-full flex flex-col bg-neutral-700 rounded-lg shadow-md`}>
|
||||
{ loading ?
|
||||
<div css={tw`w-full flex flex-col items-center justify-center`} style={{ height: '24rem' }}>
|
||||
<Spinner/>
|
||||
<Spinner size={'base'}/>
|
||||
</div>
|
||||
:
|
||||
keys.length < 1 ?
|
||||
|
|
173
resources/scripts/components/admin/api/NewApiKeyButton.tsx
Normal file
173
resources/scripts/components/admin/api/NewApiKeyButton.tsx
Normal file
|
@ -0,0 +1,173 @@
|
|||
import Button from '@/components/elements/Button';
|
||||
import Field from '@/components/elements/Field';
|
||||
import Modal from '@/components/elements/Modal';
|
||||
import FlashMessageRender from '@/components/FlashMessageRender';
|
||||
import useFlash from '@/plugins/useFlash';
|
||||
import { Form, Formik, FormikHelpers } from 'formik';
|
||||
import React, { useState } from 'react';
|
||||
import tw from 'twin.macro';
|
||||
import { object } from 'yup';
|
||||
|
||||
interface Values {
|
||||
description: string,
|
||||
}
|
||||
|
||||
const schema = object().shape({
|
||||
|
||||
});
|
||||
|
||||
export default () => {
|
||||
const [ visible, setVisible ] = useState(false);
|
||||
const { clearFlashes } = useFlash();
|
||||
|
||||
const submit = (values: Values, { setSubmitting }: FormikHelpers<Values>) => {
|
||||
clearFlashes('api:create');
|
||||
|
||||
console.log(values);
|
||||
setSubmitting(true);
|
||||
|
||||
setTimeout(() => {
|
||||
setVisible(false);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Formik
|
||||
onSubmit={submit}
|
||||
initialValues={{ description: '' }}
|
||||
validationSchema={schema}
|
||||
>
|
||||
{
|
||||
({ isSubmitting, resetForm }) => (
|
||||
<Modal
|
||||
visible={visible}
|
||||
dismissable={!isSubmitting}
|
||||
showSpinnerOverlay={isSubmitting}
|
||||
onDismissed={() => {
|
||||
resetForm();
|
||||
setVisible(false);
|
||||
}}
|
||||
>
|
||||
<FlashMessageRender byKey={'api:create'} css={tw`mb-6`}/>
|
||||
<h2 css={tw`text-2xl mb-6`}>New API Key</h2>
|
||||
<Form css={tw`m-0`}>
|
||||
<Field
|
||||
type={'string'}
|
||||
id={'description'}
|
||||
name={'description'}
|
||||
label={'Description'}
|
||||
description={'A descriptive note for this API Key.'}
|
||||
/>
|
||||
|
||||
<div css={tw`w-full flex flex-col mt-6`}>
|
||||
<div css={tw`h-10 w-full flex flex-row items-center bg-neutral-900 rounded-t-md px-4`}>
|
||||
<p css={tw`text-sm text-neutral-300 uppercase`}>Permissions</p>
|
||||
|
||||
<div css={tw`flex flex-row space-x-4 ml-auto`}>
|
||||
<span css={tw`text-xs text-neutral-300 cursor-pointer`}>None</span>
|
||||
<span css={tw`text-xs text-neutral-300 cursor-pointer`}>Read</span>
|
||||
<span css={tw`text-xs text-neutral-300 cursor-pointer`}>Write</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div css={tw`w-full flex flex-col bg-neutral-700 rounded-b-md py-1 px-4`}>
|
||||
<div css={tw`w-full flex flex-row items-center py-1`}>
|
||||
<p css={tw`text-sm text-neutral-200`}>Allocations</p>
|
||||
|
||||
<div css={tw`flex space-x-6 ml-auto`}>
|
||||
<div css={tw`flex pr-1`}>
|
||||
<input type={'radio'} name={'allocations'} css={tw`h-5 w-5`} value={'0'}/>
|
||||
</div>
|
||||
|
||||
<div css={tw`flex`}>
|
||||
<input type={'radio'} name={'allocations'} css={tw`h-5 w-5`} value={'1'}/>
|
||||
</div>
|
||||
|
||||
<div css={tw`flex pr-1`}>
|
||||
<input type={'radio'} name={'allocations'} css={tw`h-5 w-5`} value={'2'}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div css={tw`w-full flex flex-row items-center py-1`}>
|
||||
<p css={tw`text-sm text-neutral-200`}>Databases</p>
|
||||
|
||||
<div css={tw`flex space-x-6 ml-auto`}>
|
||||
<div css={tw`flex pr-1`}>
|
||||
<input type={'radio'} name={'databases'} css={tw`h-5 w-5`} value={'0'}/>
|
||||
</div>
|
||||
|
||||
<div css={tw`flex`}>
|
||||
<input type={'radio'} name={'databases'} css={tw`h-5 w-5`} value={'1'}/>
|
||||
</div>
|
||||
|
||||
<div css={tw`flex pr-1`}>
|
||||
<input type={'radio'} name={'databases'} css={tw`h-5 w-5`} value={'2'}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div css={tw`w-full flex flex-row items-center py-1`}>
|
||||
<p css={tw`text-sm text-neutral-200`}>Eggs</p>
|
||||
|
||||
<div css={tw`flex space-x-6 ml-auto`}>
|
||||
<div css={tw`flex pr-1`}>
|
||||
<input type={'radio'} name={'eggs'} css={tw`h-5 w-5`} value={'0'}/>
|
||||
</div>
|
||||
|
||||
<div css={tw`flex`}>
|
||||
<input type={'radio'} name={'eggs'} css={tw`h-5 w-5`} value={'1'}/>
|
||||
</div>
|
||||
|
||||
<div css={tw`flex pr-1`}>
|
||||
<input type={'radio'} name={'eggs'} css={tw`h-5 w-5`} value={'2'}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div css={tw`w-full flex flex-row items-center py-1`}>
|
||||
<p css={tw`text-sm text-neutral-200`}>Locations</p>
|
||||
|
||||
<div css={tw`flex space-x-6 ml-auto`}>
|
||||
<div css={tw`flex pr-1`}>
|
||||
<input type={'radio'} name={'locations'} css={tw`h-5 w-5`} value={'0'}/>
|
||||
</div>
|
||||
|
||||
<div css={tw`flex`}>
|
||||
<input type={'radio'} name={'locations'} css={tw`h-5 w-5`} value={'1'}/>
|
||||
</div>
|
||||
|
||||
<div css={tw`flex pr-1`}>
|
||||
<input type={'radio'} name={'locations'} css={tw`h-5 w-5`} value={'2'}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div css={tw`flex flex-wrap justify-end mt-6`}>
|
||||
<Button
|
||||
type={'button'}
|
||||
isSecondary
|
||||
css={tw`w-full sm:w-auto sm:mr-2`}
|
||||
onClick={() => setVisible(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button css={tw`w-full mt-4 sm:w-auto sm:mt-0`} type={'submit'}>
|
||||
Create API Key
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
</Formik>
|
||||
|
||||
<Button type={'button'} size={'large'} css={tw`h-10 ml-auto px-4 py-0`} onClick={() => setVisible(true)}>
|
||||
New API Key
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -1,3 +1,4 @@
|
|||
import Button from '@/components/elements/Button';
|
||||
import React from 'react';
|
||||
import tw from 'twin.macro';
|
||||
import AdminContentBlock from '@/components/admin/AdminContentBlock';
|
||||
|
@ -5,9 +6,15 @@ import AdminContentBlock from '@/components/admin/AdminContentBlock';
|
|||
export default () => {
|
||||
return (
|
||||
<AdminContentBlock>
|
||||
<div>
|
||||
<h2 css={tw`text-2xl text-neutral-50 font-header font-medium`}>Mounts</h2>
|
||||
<p css={tw`text-base text-neutral-400`}>Configure and manage additional mount points for servers.</p>
|
||||
<div css={tw`w-full flex flex-row items-center`}>
|
||||
<div css={tw`flex flex-col`}>
|
||||
<h2 css={tw`text-2xl text-neutral-50 font-header font-medium`}>Mounts</h2>
|
||||
<p css={tw`text-base text-neutral-400`}>Configure and manage additional mount points for servers.</p>
|
||||
</div>
|
||||
|
||||
<Button type={'button'} size={'large'} css={tw`h-10 ml-auto px-4 py-0`}>
|
||||
New Mount
|
||||
</Button>
|
||||
</div>
|
||||
</AdminContentBlock>
|
||||
);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import Button from '@/components/elements/Button';
|
||||
import React from 'react';
|
||||
import tw from 'twin.macro';
|
||||
import AdminContentBlock from '@/components/admin/AdminContentBlock';
|
||||
|
@ -5,9 +6,15 @@ import AdminContentBlock from '@/components/admin/AdminContentBlock';
|
|||
export default () => {
|
||||
return (
|
||||
<AdminContentBlock>
|
||||
<div>
|
||||
<h2 css={tw`text-2xl text-neutral-50 font-header font-medium`}>Nests</h2>
|
||||
<p css={tw`text-base text-neutral-400`}>All nests currently available on this system.</p>
|
||||
<div css={tw`w-full flex flex-row items-center`}>
|
||||
<div css={tw`flex flex-col`}>
|
||||
<h2 css={tw`text-2xl text-neutral-50 font-header font-medium`}>Nests</h2>
|
||||
<p css={tw`text-base text-neutral-400`}>All nests currently available on this system.</p>
|
||||
</div>
|
||||
|
||||
<Button type={'button'} size={'large'} css={tw`h-10 ml-auto px-4 py-0`}>
|
||||
New Nest
|
||||
</Button>
|
||||
</div>
|
||||
</AdminContentBlock>
|
||||
);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import Button from '@/components/elements/Button';
|
||||
import React from 'react';
|
||||
import tw from 'twin.macro';
|
||||
import AdminContentBlock from '@/components/admin/AdminContentBlock';
|
||||
|
@ -5,9 +6,15 @@ import AdminContentBlock from '@/components/admin/AdminContentBlock';
|
|||
export default () => {
|
||||
return (
|
||||
<AdminContentBlock>
|
||||
<div>
|
||||
<h2 css={tw`text-2xl text-neutral-50 font-header font-medium`}>Nodes</h2>
|
||||
<p css={tw`text-base text-neutral-400`}>All nodes available on the system.</p>
|
||||
<div css={tw`w-full flex flex-row items-center`}>
|
||||
<div css={tw`flex flex-col`}>
|
||||
<h2 css={tw`text-2xl text-neutral-50 font-header font-medium`}>Nodes</h2>
|
||||
<p css={tw`text-base text-neutral-400`}>All nodes available on the system.</p>
|
||||
</div>
|
||||
|
||||
<Button type={'button'} size={'large'} css={tw`h-10 ml-auto px-4 py-0`}>
|
||||
New Node
|
||||
</Button>
|
||||
</div>
|
||||
</AdminContentBlock>
|
||||
);
|
||||
|
|
99
resources/scripts/components/admin/roles/RolesContainer.tsx
Normal file
99
resources/scripts/components/admin/roles/RolesContainer.tsx
Normal file
|
@ -0,0 +1,99 @@
|
|||
import { httpErrorToHuman } from '@/api/http';
|
||||
import FlashMessageRender from '@/components/FlashMessageRender';
|
||||
import useFlash from '@/plugins/useFlash';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import Button from '@/components/elements/Button';
|
||||
import tw from 'twin.macro';
|
||||
import AdminContentBlock from '@/components/admin/AdminContentBlock';
|
||||
import Spinner from '@/components/elements/Spinner';
|
||||
import getRoles, { Role } from '@/api/admin/roles/getRoles';
|
||||
|
||||
export default () => {
|
||||
const { clearFlashes, addError } = useFlash();
|
||||
const [ loading, setLoading ] = useState<boolean>(true);
|
||||
const [ roles, setRoles ] = useState<Role[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
clearFlashes('roles');
|
||||
|
||||
getRoles()
|
||||
.then(roles => setRoles(roles))
|
||||
.catch(error => {
|
||||
addError({ message: httpErrorToHuman(error), key: 'roles' });
|
||||
console.error(error);
|
||||
})
|
||||
.then(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AdminContentBlock>
|
||||
<div css={tw`w-full flex flex-row items-center mb-8`}>
|
||||
<div css={tw`flex flex-col`}>
|
||||
<h2 css={tw`text-2xl text-neutral-50 font-header font-medium`}>Roles</h2>
|
||||
<p css={tw`text-base text-neutral-400`}>Soon™</p>
|
||||
</div>
|
||||
|
||||
<Button type={'button'} size={'large'} css={tw`h-10 ml-auto px-4 py-0`}>
|
||||
New Role
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<FlashMessageRender byKey={'roles'} css={tw`mb-4`}/>
|
||||
|
||||
<div css={tw`w-full flex flex-col`}>
|
||||
<div css={tw`w-full flex flex-col bg-neutral-700 rounded-lg shadow-md`}>
|
||||
{ loading ?
|
||||
<div css={tw`w-full flex flex-col items-center justify-center`} style={{ height: '24rem' }}>
|
||||
<Spinner size={'base'}/>
|
||||
</div>
|
||||
:
|
||||
roles.length < 1 ?
|
||||
<div css={tw`w-full flex flex-col items-center justify-center pb-6 py-2 sm:py-8 md:py-10 px-8`}>
|
||||
<div css={tw`h-64 flex`}>
|
||||
<img src={'/assets/svgs/not_found.svg'} alt={'No Items'} css={tw`h-full select-none`}/>
|
||||
</div>
|
||||
|
||||
<p css={tw`text-lg text-neutral-300 text-center font-normal sm:mt-8`}>No items could be found, it's almost like they are hiding.</p>
|
||||
</div>
|
||||
:
|
||||
<div css={tw`overflow-x-auto`}>
|
||||
<table css={tw`w-full table-auto`}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th css={tw`py-4 px-4 text-left pl-8`}>
|
||||
<span css={tw`font-medium text-base text-neutral-300 text-left whitespace-no-wrap mr-2`}>ID</span>
|
||||
</th>
|
||||
|
||||
<th css={tw`py-4 px-4 text-left`}>
|
||||
<span css={tw`font-medium text-base text-neutral-300 text-left whitespace-no-wrap mr-2`}>Name</span>
|
||||
</th>
|
||||
|
||||
<th css={tw`py-4 px-4 text-left pr-8`}>
|
||||
<span css={tw`font-medium text-base text-neutral-300 text-left whitespace-no-wrap mr-2`}>Description</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody css={tw`bg-neutral-600`}>
|
||||
{
|
||||
roles.map(role => (
|
||||
<tr key={role.id} css={tw`h-12 cursor-pointer`}>
|
||||
<td css={tw`py-3 px-4 text-neutral-200 text-left whitespace-no-wrap pl-8`}>{role.id}</td>
|
||||
<td css={tw`py-3 px-4 text-neutral-200 text-left whitespace-no-wrap`}>{role.name}</td>
|
||||
<td css={tw`py-3 px-4 text-neutral-200 text-left whitespace-no-wrap pr-8`}>{role.description}</td>
|
||||
</tr>
|
||||
))
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div css={tw`h-12 w-full flex flex-row items-center justify-between px-6`}>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</AdminContentBlock>
|
||||
);
|
||||
};
|
|
@ -1,3 +1,4 @@
|
|||
import Button from '@/components/elements/Button';
|
||||
import React from 'react';
|
||||
import tw from 'twin.macro';
|
||||
import AdminContentBlock from '@/components/admin/AdminContentBlock';
|
||||
|
@ -5,9 +6,15 @@ import AdminContentBlock from '@/components/admin/AdminContentBlock';
|
|||
export default () => {
|
||||
return (
|
||||
<AdminContentBlock>
|
||||
<div>
|
||||
<h2 css={tw`text-2xl text-neutral-50 font-header font-medium`}>Servers</h2>
|
||||
<p css={tw`text-base text-neutral-400`}>All servers available on the system.</p>
|
||||
<div css={tw`w-full flex flex-row items-center`}>
|
||||
<div css={tw`flex flex-col`}>
|
||||
<h2 css={tw`text-2xl text-neutral-50 font-header font-medium`}>Servers</h2>
|
||||
<p css={tw`text-base text-neutral-400`}>All servers available on the system.</p>
|
||||
</div>
|
||||
|
||||
<Button type={'button'} size={'large'} css={tw`h-10 ml-auto px-4 py-0`}>
|
||||
New Server
|
||||
</Button>
|
||||
</div>
|
||||
</AdminContentBlock>
|
||||
);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import Button from '@/components/elements/Button';
|
||||
import React from 'react';
|
||||
import tw from 'twin.macro';
|
||||
import AdminContentBlock from '@/components/admin/AdminContentBlock';
|
||||
|
@ -5,9 +6,15 @@ import AdminContentBlock from '@/components/admin/AdminContentBlock';
|
|||
export default () => {
|
||||
return (
|
||||
<AdminContentBlock>
|
||||
<div>
|
||||
<h2 css={tw`text-2xl text-neutral-50 font-header font-medium`}>Users</h2>
|
||||
<p css={tw`text-base text-neutral-400`}>All registered users on the system.</p>
|
||||
<div css={tw`w-full flex flex-row items-center`}>
|
||||
<div css={tw`flex flex-col`}>
|
||||
<h2 css={tw`text-2xl text-neutral-50 font-header font-medium`}>Users</h2>
|
||||
<p css={tw`text-base text-neutral-400`}>All registered users on the system.</p>
|
||||
</div>
|
||||
|
||||
<Button type={'button'} size={'large'} css={tw`h-10 ml-auto px-4 py-0`}>
|
||||
New User
|
||||
</Button>
|
||||
</div>
|
||||
</AdminContentBlock>
|
||||
);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import RolesContainer from '@/components/admin/roles/RolesContainer';
|
||||
import React, { useState } from 'react';
|
||||
import { NavLink, Route, RouteComponentProps, Switch } from 'react-router-dom';
|
||||
import NotFound from '@/components/screens/NotFound';
|
||||
|
@ -126,6 +127,10 @@ export default ({ location, match }: RouteComponentProps) => {
|
|||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" /></svg>
|
||||
<span>Users</span>
|
||||
</NavLink>
|
||||
<NavLink to={`${match.url}/roles`}>
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" /></svg>
|
||||
<span>Roles</span>
|
||||
</NavLink>
|
||||
|
||||
<span>Service Management</span>
|
||||
|
||||
|
@ -144,7 +149,7 @@ export default ({ location, match }: RouteComponentProps) => {
|
|||
</NavLink>
|
||||
|
||||
<div className={'user'}>
|
||||
<img src={'https://cdn.krygon.app/avatars/52564280420073473/7db9f06013ec39f7fa5c1e79241c43afa1f152d82cbb193ecaab7753b9a3e61e?size=64'} alt="Profile Picture" css={tw`h-10 w-10 rounded-full select-none`} />
|
||||
<img src={'https://www.gravatar.com/avatar/78a6a270ec41715a8ae96c02b8961f9e?s=64'} alt="Profile Picture" css={tw`h-10 w-10 rounded-full select-none`} />
|
||||
|
||||
<div css={tw`flex flex-col ml-4`}>
|
||||
<span css={tw`font-header font-medium text-sm text-neutral-50 whitespace-no-wrap leading-tight select-none`}>Matthew Penner</span>
|
||||
|
@ -170,6 +175,7 @@ export default ({ location, match }: RouteComponentProps) => {
|
|||
<Route path={`${match.path}/nodes`} component={NodesContainer}/>
|
||||
<Route path={`${match.path}/servers`} component={ServersContainer}/>
|
||||
<Route path={`${match.path}/users`} component={UsersContainer}/>
|
||||
<Route path={`${match.path}/roles`} component={RolesContainer}/>
|
||||
|
||||
<Route path={`${match.path}/nests`} component={NestsContainer}/>
|
||||
<Route path={`${match.path}/mounts`} component={MountsContainer}/>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/', 'BaseController@index')->name('admin.index')->fallback();
|
||||
Route::get('/{react}', 'BaseController@index');
|
||||
//Route::get('/{react}', 'BaseController@index');
|
||||
|
||||
Route::get('/statistics', 'StatisticsController@index')->name('admin.statistics');
|
||||
|
||||
|
@ -16,8 +16,8 @@ Route::get('/statistics', 'StatisticsController@index')->name('admin.statistics'
|
|||
|
|
||||
*/
|
||||
Route::group(['prefix' => 'api'], function () {
|
||||
//Route::get('/', 'ApiController@index')->name('admin.api.index');
|
||||
//Route::get('/new', 'ApiController@create')->name('admin.api.new');
|
||||
Route::get('/', 'ApiController@index')->name('admin.api.index');
|
||||
Route::get('/new', 'ApiController@create')->name('admin.api.new');
|
||||
|
||||
Route::post('/new', 'ApiController@store');
|
||||
|
||||
|
@ -33,8 +33,8 @@ Route::group(['prefix' => 'api'], function () {
|
|||
|
|
||||
*/
|
||||
Route::group(['prefix' => 'locations'], function () {
|
||||
//Route::get('/', 'LocationController@index')->name('admin.locations');
|
||||
//Route::get('/view/{location}', 'LocationController@view')->name('admin.locations.view');
|
||||
Route::get('/', 'LocationController@index')->name('admin.locations');
|
||||
Route::get('/view/{location}', 'LocationController@view')->name('admin.locations.view');
|
||||
|
||||
Route::post('/', 'LocationController@create');
|
||||
Route::patch('/view/{location}', 'LocationController@update');
|
||||
|
@ -49,8 +49,8 @@ Route::group(['prefix' => 'locations'], function () {
|
|||
|
|
||||
*/
|
||||
Route::group(['prefix' => 'databases'], function () {
|
||||
//Route::get('/', 'DatabaseController@index')->name('admin.databases');
|
||||
//Route::get('/view/{host}', 'DatabaseController@view')->name('admin.databases.view');
|
||||
Route::get('/', 'DatabaseController@index')->name('admin.databases');
|
||||
Route::get('/view/{host}', 'DatabaseController@view')->name('admin.databases.view');
|
||||
|
||||
Route::post('/', 'DatabaseController@create');
|
||||
Route::patch('/view/{host}', 'DatabaseController@update');
|
||||
|
@ -66,10 +66,10 @@ Route::group(['prefix' => 'databases'], function () {
|
|||
|
|
||||
*/
|
||||
Route::group(['prefix' => 'settings'], function () {
|
||||
//Route::get('/', 'Settings\IndexController@index')->name('admin.settings');
|
||||
//Route::get('/mail', 'Settings\MailController@index')->name('admin.settings.mail');
|
||||
//Route::get('/mail/test', 'Settings\MailController@test')->name('admin.settings.mail.test');
|
||||
//Route::get('/advanced', 'Settings\AdvancedController@index')->name('admin.settings.advanced');
|
||||
Route::get('/', 'Settings\IndexController@index')->name('admin.settings');
|
||||
Route::get('/mail', 'Settings\MailController@index')->name('admin.settings.mail');
|
||||
Route::get('/mail/test', 'Settings\MailController@test')->name('admin.settings.mail.test');
|
||||
Route::get('/advanced', 'Settings\AdvancedController@index')->name('admin.settings.advanced');
|
||||
|
||||
Route::patch('/', 'Settings\IndexController@update');
|
||||
Route::patch('/mail', 'Settings\MailController@update');
|
||||
|
@ -85,10 +85,10 @@ Route::group(['prefix' => 'settings'], function () {
|
|||
|
|
||||
*/
|
||||
Route::group(['prefix' => 'users'], function () {
|
||||
//Route::get('/', 'UserController@index')->name('admin.users');
|
||||
//Route::get('/accounts.json', 'UserController@json')->name('admin.users.json');
|
||||
//Route::get('/new', 'UserController@create')->name('admin.users.new');
|
||||
//Route::get('/view/{user}', 'UserController@view')->name('admin.users.view');
|
||||
Route::get('/', 'UserController@index')->name('admin.users');
|
||||
Route::get('/accounts.json', 'UserController@json')->name('admin.users.json');
|
||||
Route::get('/new', 'UserController@create')->name('admin.users.new');
|
||||
Route::get('/view/{user}', 'UserController@view')->name('admin.users.view');
|
||||
|
||||
Route::post('/new', 'UserController@store');
|
||||
Route::patch('/view/{user}', 'UserController@update');
|
||||
|
@ -105,20 +105,20 @@ Route::group(['prefix' => 'users'], function () {
|
|||
|
|
||||
*/
|
||||
Route::group(['prefix' => 'servers'], function () {
|
||||
//Route::get('/', 'Servers\ServerController@index')->name('admin.servers');
|
||||
//Route::get('/new', 'Servers\CreateServerController@index')->name('admin.servers.new');
|
||||
//Route::get('/view/{server}', 'Servers\ServerViewController@index')->name('admin.servers.view');
|
||||
Route::get('/', 'Servers\ServerController@index')->name('admin.servers');
|
||||
Route::get('/new', 'Servers\CreateServerController@index')->name('admin.servers.new');
|
||||
Route::get('/view/{server}', 'Servers\ServerViewController@index')->name('admin.servers.view');
|
||||
|
||||
/*Route::group(['middleware' => [ServerInstalled::class]], function () {
|
||||
Route::group(['middleware' => [ServerInstalled::class]], function () {
|
||||
Route::get('/view/{server}/details', 'Servers\ServerViewController@details')->name('admin.servers.view.details');
|
||||
Route::get('/view/{server}/build', 'Servers\ServerViewController@build')->name('admin.servers.view.build');
|
||||
Route::get('/view/{server}/startup', 'Servers\ServerViewController@startup')->name('admin.servers.view.startup');
|
||||
Route::get('/view/{server}/database', 'Servers\ServerViewController@database')->name('admin.servers.view.database');
|
||||
Route::get('/view/{server}/mounts', 'Servers\ServerViewController@mounts')->name('admin.servers.view.mounts');
|
||||
});*/
|
||||
});
|
||||
|
||||
//Route::get('/view/{server}/manage', 'Servers\ServerViewController@manage')->name('admin.servers.view.manage');
|
||||
//Route::get('/view/{server}/delete', 'Servers\ServerViewController@delete')->name('admin.servers.view.delete');
|
||||
Route::get('/view/{server}/manage', 'Servers\ServerViewController@manage')->name('admin.servers.view.manage');
|
||||
Route::get('/view/{server}/delete', 'Servers\ServerViewController@delete')->name('admin.servers.view.delete');
|
||||
|
||||
Route::post('/new', 'Servers\CreateServerController@store');
|
||||
Route::post('/view/{server}/build', 'ServersController@updateBuild');
|
||||
|
@ -147,15 +147,15 @@ Route::group(['prefix' => 'servers'], function () {
|
|||
|
|
||||
*/
|
||||
Route::group(['prefix' => 'nodes'], function () {
|
||||
//Route::get('/', 'Nodes\NodeController@index')->name('admin.nodes');
|
||||
//Route::get('/new', 'NodesController@create')->name('admin.nodes.new');
|
||||
//Route::get('/view/{node}', 'Nodes\NodeViewController@index')->name('admin.nodes.view');
|
||||
//Route::get('/view/{node}/settings', 'Nodes\NodeViewController@settings')->name('admin.nodes.view.settings');
|
||||
//Route::get('/view/{node}/configuration', 'Nodes\NodeViewController@configuration')->name('admin.nodes.view.configuration');
|
||||
//Route::get('/view/{node}/allocation', 'Nodes\NodeViewController@allocations')->name('admin.nodes.view.allocation');
|
||||
//Route::get('/view/{node}/servers', 'Nodes\NodeViewController@servers')->name('admin.nodes.view.servers');
|
||||
//Route::get('/view/{node}/system-information', 'Nodes\SystemInformationController');
|
||||
//Route::get('/view/{node}/settings/token', 'NodeAutoDeployController')->name('admin.nodes.view.configuration.token');
|
||||
Route::get('/', 'Nodes\NodeController@index')->name('admin.nodes');
|
||||
Route::get('/new', 'NodesController@create')->name('admin.nodes.new');
|
||||
Route::get('/view/{node}', 'Nodes\NodeViewController@index')->name('admin.nodes.view');
|
||||
Route::get('/view/{node}/settings', 'Nodes\NodeViewController@settings')->name('admin.nodes.view.settings');
|
||||
Route::get('/view/{node}/configuration', 'Nodes\NodeViewController@configuration')->name('admin.nodes.view.configuration');
|
||||
Route::get('/view/{node}/allocation', 'Nodes\NodeViewController@allocations')->name('admin.nodes.view.allocation');
|
||||
Route::get('/view/{node}/servers', 'Nodes\NodeViewController@servers')->name('admin.nodes.view.servers');
|
||||
Route::get('/view/{node}/system-information', 'Nodes\SystemInformationController');
|
||||
Route::get('/view/{node}/settings/token', 'NodeAutoDeployController')->name('admin.nodes.view.configuration.token');
|
||||
|
||||
Route::post('/new', 'NodesController@store');
|
||||
Route::post('/view/{node}/allocation', 'NodesController@createAllocation');
|
||||
|
@ -178,8 +178,8 @@ Route::group(['prefix' => 'nodes'], function () {
|
|||
|
|
||||
*/
|
||||
Route::group(['prefix' => 'mounts'], function () {
|
||||
//Route::get('/', 'MountController@index')->name('admin.mounts');
|
||||
//Route::get('/view/{mount}', 'MountController@view')->name('admin.mounts.view');
|
||||
Route::get('/', 'MountController@index')->name('admin.mounts');
|
||||
Route::get('/view/{mount}', 'MountController@view')->name('admin.mounts.view');
|
||||
|
||||
Route::post('/', 'MountController@create');
|
||||
Route::post('/{mount}/eggs', 'MountController@addEggs')->name('admin.mounts.eggs');
|
||||
|
@ -200,14 +200,14 @@ Route::group(['prefix' => 'mounts'], function () {
|
|||
|
|
||||
*/
|
||||
Route::group(['prefix' => 'nests'], function () {
|
||||
//Route::get('/', 'Nests\NestController@index')->name('admin.nests');
|
||||
//Route::get('/new', 'Nests\NestController@create')->name('admin.nests.new');
|
||||
//Route::get('/view/{nest}', 'Nests\NestController@view')->name('admin.nests.view');
|
||||
//Route::get('/egg/new', 'Nests\EggController@create')->name('admin.nests.egg.new');
|
||||
//Route::get('/egg/{egg}', 'Nests\EggController@view')->name('admin.nests.egg.view');
|
||||
//Route::get('/egg/{egg}/export', 'Nests\EggShareController@export')->name('admin.nests.egg.export');
|
||||
//Route::get('/egg/{egg}/variables', 'Nests\EggVariableController@view')->name('admin.nests.egg.variables');
|
||||
//Route::get('/egg/{egg}/scripts', 'Nests\EggScriptController@index')->name('admin.nests.egg.scripts');
|
||||
Route::get('/', 'Nests\NestController@index')->name('admin.nests');
|
||||
Route::get('/new', 'Nests\NestController@create')->name('admin.nests.new');
|
||||
Route::get('/view/{nest}', 'Nests\NestController@view')->name('admin.nests.view');
|
||||
Route::get('/egg/new', 'Nests\EggController@create')->name('admin.nests.egg.new');
|
||||
Route::get('/egg/{egg}', 'Nests\EggController@view')->name('admin.nests.egg.view');
|
||||
Route::get('/egg/{egg}/export', 'Nests\EggShareController@export')->name('admin.nests.egg.export');
|
||||
Route::get('/egg/{egg}/variables', 'Nests\EggVariableController@view')->name('admin.nests.egg.variables');
|
||||
Route::get('/egg/{egg}/scripts', 'Nests\EggScriptController@index')->name('admin.nests.egg.scripts');
|
||||
|
||||
Route::post('/new', 'Nests\NestController@store');
|
||||
Route::post('/import', 'Nests\EggShareController@import')->name('admin.nests.egg.import');
|
||||
|
@ -225,3 +225,13 @@ Route::group(['prefix' => 'nests'], function () {
|
|||
Route::delete('/egg/{egg}', 'Nests\EggController@destroy');
|
||||
Route::delete('/egg/{egg}/variables/{variable}', 'Nests\EggVariableController@destroy');
|
||||
});
|
||||
|
||||
Route::group(['prefix' => 'roles'], function () {
|
||||
Route::get('/', 'RolesController@index')->name('admin.roles');
|
||||
|
||||
Route::post('/', 'RolesController@create');
|
||||
|
||||
Route::patch('/', 'RolesController@update');
|
||||
|
||||
Route::delete('/', 'RolesController@delete');
|
||||
});
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Routes
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
|
|
Loading…
Add table
Reference in a new issue