A few adjustments for chunking the new file edit page

This commit is contained in:
Dane Everitt 2019-09-28 14:59:05 -07:00
parent 8599e2c64b
commit c66d2cd123
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
9 changed files with 72 additions and 28 deletions

View File

@ -44,7 +44,7 @@ use Znck\Eloquent\Traits\BelongsToThrough;
* @property \Pterodactyl\Models\Node $node * @property \Pterodactyl\Models\Node $node
* @property \Pterodactyl\Models\Nest $nest * @property \Pterodactyl\Models\Nest $nest
* @property \Pterodactyl\Models\Egg $egg * @property \Pterodactyl\Models\Egg $egg
* @property \Pterodactyl\Models\EggVariable[]|\Illuminate\Support\Collection $variables * @property \Pterodactyl\Models\ServerVariable[]|\Illuminate\Support\Collection $variables
* @property \Pterodactyl\Models\Schedule[]|\Illuminate\Support\Collection $schedule * @property \Pterodactyl\Models\Schedule[]|\Illuminate\Support\Collection $schedule
* @property \Pterodactyl\Models\Database[]|\Illuminate\Support\Collection $databases * @property \Pterodactyl\Models\Database[]|\Illuminate\Support\Collection $databases
* @property \Pterodactyl\Models\Location $location * @property \Pterodactyl\Models\Location $location

View File

@ -0,0 +1,9 @@
import http from '@/api/http';
export default (server: string, file: string): Promise<string> => {
return new Promise((resolve, reject) => {
http.get(`/api/client/servers/${server}/files/contents`, { params: { file } })
.then(({ data }) => resolve(data))
.catch(reject);
});
};

View File

@ -0,0 +1,14 @@
import React, { Suspense } from 'react';
import Spinner from '@/components/elements/Spinner';
export default ({ children }: { children?: React.ReactNode }) => (
<Suspense
fallback={
<div className={'mx-4 w-3/4 mr-4 flex items-center justify-center'}>
<Spinner centered={true} size={'normal'}/>
</div>
}
>
{children}
</Suspense>
);

View File

@ -8,7 +8,7 @@ import styled from 'styled-components';
import { faMemory } from '@fortawesome/free-solid-svg-icons/faMemory'; import { faMemory } from '@fortawesome/free-solid-svg-icons/faMemory';
import { faMicrochip } from '@fortawesome/free-solid-svg-icons/faMicrochip'; import { faMicrochip } from '@fortawesome/free-solid-svg-icons/faMicrochip';
import { bytesToHuman } from '@/helpers'; import { bytesToHuman } from '@/helpers';
import Spinner from '@/components/elements/Spinner'; import SuspenseSpinner from '@/components/elements/SuspenseSpinner';
type PowerAction = 'start' | 'stop' | 'restart' | 'kill'; type PowerAction = 'start' | 'stop' | 'restart' | 'kill';
@ -23,8 +23,8 @@ const StopOrKillButton = ({ onPress }: { onPress: (action: PowerAction) => void
const status = ServerContext.useStoreState(state => state.status.value); const status = ServerContext.useStoreState(state => state.status.value);
useEffect(() => { useEffect(() => {
setClicked(state => ['stopping'].indexOf(status) < 0 ? false : state); setClicked(state => [ 'stopping' ].indexOf(status) < 0 ? false : state);
}, [status]); }, [ status ]);
return ( return (
<button <button
@ -142,17 +142,11 @@ export default () => {
<StopOrKillButton onPress={action => sendPowerCommand(action)}/> <StopOrKillButton onPress={action => sendPowerCommand(action)}/>
</GreyBox> </GreyBox>
</div> </div>
<React.Suspense <SuspenseSpinner>
fallback={
<div className={'mx-4 w-3/4 mr-4 flex items-center justify-center'}>
<Spinner centered={true} size={'normal'}/>
</div>
}
>
<div className={'mx-4 w-3/4 mr-4'}> <div className={'mx-4 w-3/4 mr-4'}>
<ChunkedConsole/> <ChunkedConsole/>
</div> </div>
</React.Suspense> </SuspenseSpinner>
</div> </div>
); );
}; };

View File

@ -1,16 +1,25 @@
import React from 'react'; import React, { useEffect, useState } from 'react';
import useRouter from 'use-react-router'; import useRouter from 'use-react-router';
import queryString from 'query-string'; import { ServerContext } from '@/state/server';
import getFileContents from '@/api/server/files/getFileContents';
export default () => { export default () => {
const { location: { search } } = useRouter(); const { location: { hash } } = useRouter();
const values = queryString.parse(search); const [content, setContent] = useState('');
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
useEffect(() => {
getFileContents(uuid, hash.replace(/^#/, ''))
.then(setContent)
.catch(error => console.error(error));
}, []);
return ( return (
<div className={'my-10'}> <div className={'my-10'}>
<textarea className={'rounded bg-black h-32 w-full text-neutral-100'}> <textarea
value={content}
</textarea> className={'rounded bg-black h-32 w-full text-neutral-100 text-sm font-mono'}
/>
</div> </div>
); );
}; };

View File

@ -10,10 +10,13 @@ import React from 'react';
import { FileObject } from '@/api/server/files/loadDirectory'; import { FileObject } from '@/api/server/files/loadDirectory';
import FileDropdownMenu from '@/components/server/files/FileDropdownMenu'; import FileDropdownMenu from '@/components/server/files/FileDropdownMenu';
import { ServerContext } from '@/state/server'; import { ServerContext } from '@/state/server';
import { NavLink } from 'react-router-dom';
import useRouter from 'use-react-router';
export default ({ file }: { file: FileObject }) => { export default ({ file }: { file: FileObject }) => {
const directory = ServerContext.useStoreState(state => state.files.directory); const directory = ServerContext.useStoreState(state => state.files.directory);
const setDirectory = ServerContext.useStoreActions(actions => actions.files.setDirectory); const setDirectory = ServerContext.useStoreActions(actions => actions.files.setDirectory);
const { match } = useRouter();
return ( return (
<div <div
@ -23,18 +26,18 @@ export default ({ file }: { file: FileObject }) => {
hover:text-neutral-100 cursor-pointer items-center no-underline hover:bg-neutral-600 hover:text-neutral-100 cursor-pointer items-center no-underline hover:bg-neutral-600
`} `}
> >
<a <NavLink
href={file.isFile ? undefined : `#${directory}/${file.name}`} to={`${match.url}/${file.isFile ? 'edit/' : ''}#${directory}/${file.name}`}
className={'flex flex-1 text-neutral-300 no-underline p-3'} className={'flex flex-1 text-neutral-300 no-underline p-3'}
onClick={e => { onClick={e => {
e.preventDefault();
// Don't rely on the onClick to work with the generated URL. Because of the way this // Don't rely on the onClick to work with the generated URL. Because of the way this
// component re-renders you'll get redirected into a nested directory structure since // component re-renders you'll get redirected into a nested directory structure since
// it'll cause the directory variable to update right away when you click. // it'll cause the directory variable to update right away when you click.
// //
// Just trust me future me, leave this be. // Just trust me future me, leave this be.
if (!file.isFile) { if (!file.isFile) {
e.preventDefault();
window.location.hash = `#${directory}/${file.name}`; window.location.hash = `#${directory}/${file.name}`;
setDirectory(`${directory}/${file.name}`); setDirectory(`${directory}/${file.name}`);
} }
@ -65,7 +68,7 @@ export default ({ file }: { file: FileObject }) => {
distanceInWordsToNow(file.modifiedAt, { addSuffix: true }) distanceInWordsToNow(file.modifiedAt, { addSuffix: true })
} }
</div> </div>
</a> </NavLink>
<FileDropdownMenu uuid={file.uuid}/> <FileDropdownMenu uuid={file.uuid}/>
</div> </div>
); );

View File

@ -1,4 +1,4 @@
import React, { useEffect } from 'react'; import React, { lazy, useEffect } from 'react';
import { NavLink, Route, RouteComponentProps, Switch } from 'react-router-dom'; import { NavLink, Route, RouteComponentProps, Switch } from 'react-router-dom';
import NavigationBar from '@/components/NavigationBar'; import NavigationBar from '@/components/NavigationBar';
import ServerConsole from '@/components/server/ServerConsole'; import ServerConsole from '@/components/server/ServerConsole';
@ -10,7 +10,11 @@ import { Provider } from 'react-redux';
import DatabasesContainer from '@/components/server/databases/DatabasesContainer'; import DatabasesContainer from '@/components/server/databases/DatabasesContainer';
import FileManagerContainer from '@/components/server/files/FileManagerContainer'; import FileManagerContainer from '@/components/server/files/FileManagerContainer';
import { CSSTransition } from 'react-transition-group'; import { CSSTransition } from 'react-transition-group';
import FileEditContainer from '@/components/server/files/FileEditContainer'; import SuspenseSpinner from '@/components/elements/SuspenseSpinner';
const LazyFileEditContainer = lazy<React.ComponentType<RouteComponentProps<any>>>(
() => import('@/components/server/files/FileEditContainer')
);
const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>) => { const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>) => {
const server = ServerContext.useStoreState(state => state.server.data); const server = ServerContext.useStoreState(state => state.server.data);
@ -51,7 +55,15 @@ const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>)
<Switch location={location}> <Switch location={location}>
<Route path={`${match.path}`} component={ServerConsole} exact/> <Route path={`${match.path}`} component={ServerConsole} exact/>
<Route path={`${match.path}/files`} component={FileManagerContainer} exact/> <Route path={`${match.path}/files`} component={FileManagerContainer} exact/>
<Route path={`${match.path}/files/edit`} component={FileEditContainer} exact/> <Route
path={`${match.path}/files/edit`}
render={props => (
<SuspenseSpinner>
<LazyFileEditContainer {...props}/>
</SuspenseSpinner>
)}
exact
/>
<Route path={`${match.path}/databases`} component={DatabasesContainer}/> <Route path={`${match.path}/databases`} component={DatabasesContainer}/>
</Switch> </Switch>
</React.Fragment> </React.Fragment>

View File

@ -1,5 +1,5 @@
@import url('//fonts.googleapis.com/css?family=Rubik:300,400,500&display=swap'); @import url('//fonts.googleapis.com/css?family=Rubik:300,400,500&display=swap');
@import url('https://fonts.googleapis.com/css?family=IBM+Plex+Sans:500&display=swap'); @import url('https://fonts.googleapis.com/css?family=IBM+Plex+Mono|IBM+Plex+Sans:500&display=swap');
body { body {
@apply .text-neutral-200; @apply .text-neutral-200;

View File

@ -211,6 +211,9 @@ module.exports = {
'serif', 'serif',
], ],
'mono': [ 'mono': [
'"IBM Plex Mono"',
'"Source Code Pro"',
'SourceCodePro',
'Menlo', 'Menlo',
'Monaco', 'Monaco',
'Consolas', 'Consolas',