Added installer

This commit is contained in:
Angelillo15 2022-12-16 18:47:24 +01:00
commit c337e35697
5 changed files with 675 additions and 0 deletions

111
install.sh Normal file
View File

@ -0,0 +1,111 @@
#!/bin/bash
BLUE='\033[0;34m'.
NO_COLOR='\033[0m'
if (( $EUID != 0 )); then
echo "Please run as root"
exit
fi
clear
installTheme(){
cd /var/www/
tar -cvf IceMinecraftTheme.tar.gz pterodactyl
echo "Installing theme..."
cd /var/www/pterodactyl
rm -r IceMinecraftTheme
git clone https://github.com/Angelillo15/IceMinecraftTheme.git
cd MinecraftPurpleTheme
rm /var/www/pterodactyl/resources/scripts/IceMinecraftTheme.css
rm /var/www/pterodactyl/resources/scripts/index.tsx
rm /var/www/pterodactyl/resources/scripts/components/server/console/Console.tsx
mv index.tsx /var/www/pterodactyl/resources/scripts/index.tsx
mv IceMinecraftTheme.css /var/www/pterodactyl/resources/scripts/IceMinecraftTheme.css
mv components/server/console/Console.tsx /var/www/pterodactyl/resources/scripts/components/server/console/Console.tsx
cd /var/www/pterodactyl
curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
apt update
apt install -y nodejs
npm i -g yarn
yarn
cd /var/www/pterodactyl
yarn build:production
sudo php artisan optimize:clear
}
installThemeQuestion(){
while true; do
read -p "Are you sure that you want to install the theme [y/N]? " yn
case $yn in
[Yy]* ) installTheme; break;;
[Nn]* ) exit;;
* ) exit;;
esac
done
}
repair(){
bash <(curl https://raw.githubusercontent.com/Angelillo15/IceMinecraftTheme/main/repair.sh)
}
restoreBackUp(){
echo "Restoring backup..."
cd /var/www/
tar -xvf IceMinecraftTheme.tar.gz
rm IceMinecraftTheme.tar.gz
cd /var/www/pterodactyl
yarn build:production
sudo php artisan optimize:clear
}
printf "${blue} ____ _____ ______ _________________ ____ ____ ______ ______ _______ ______ \n"
printf "${blue}| | ___|\ \ ___|\ \ / \| | | | ___|\ \ | \/ \ ___|\ \ \n"
printf "${blue}| | / /\ \ | \ \ \______ ______/| | | || \ \ / /\ \ | \ \ \n"
printf "${blue}| || | | || ,_____/| \( / / )/ | |_| || ,_____/| / /\ / /\ || ,_____/| \n"
printf "${blue}| || | |____|| \--'\_|/ ' | | ' | .-. || \--'\_|/ / /\ \_/ / / /|| \--'\_|/ \n"
printf "${blue}| || | ____ | /___/| | | | | | || /___/| | | \|_|/ / / || /___/| \n"
printf "${blue}| || | | || \____|\ / // | | | || \____|\ | | | | || \____|\ \n"
printf "${blue}|____||\ ___\/ /||____ ' /| /___// |____| |____||____ ' /||\____\ |____| /|____ ' /| \n"
printf "${blue}| || | /____/ || /_____/ | | | | | | || /_____/ || | | | | / | /_____/ | \n"
printf "${blue}|____| \|___| | /|____| | / |____| |____| |____||____| | / \|____| |____|/ |____| | / \n"
printf "${blue} \( \( |____|/ \( |_____|/ \( \( )/ \( |_____|/ \( )/ \( |_____|/ \n"
printf "${blue} ' ' )/ ' )/ ' ' ' ' )/ ' ' ' )/ \n"
printf "${blue} ' ' ' ' \n"
echo ""
echo "Copyright (c) 2022 Angelillo15 | angelillo15.es"
echo "This program is free software: you can redistribute it and/or modify"
echo ""
echo "Discord: https://discord.angelillo15.es/"
echo "Website: https://angelillo15.es/"
echo ""
echo "[1] Install theme"
echo "[2] Restore backup"
echo "[3] Repair panel (use if you have an error in the theme installation)"
echo "[4] Exit"
printf "${NO_COLOR}"
read -p "Please enter a number: " choice
if [ $choice == "1" ]
then
installThemeQuestion
fi
if [ $choice == "2" ]
then
restoreBackUp
fi
if [ $choice == "3" ]
then
repair
fi
if [ $choice == "4" ]
then
exit
fi

55
repair.sh Normal file
View File

@ -0,0 +1,55 @@
#!/bin/bash
if (( $EUID != 0 )); then
echo "Please run as root"
exit
fi
repairPanel(){
cd /var/www/pterodactyl
php artisan down
rm -r /var/www/pterodactyl/resources
curl -L https://github.com/pterodactyl/panel/releases/latest/download/panel.tar.gz | tar -xzv
chmod -R 755 storage/* bootstrap/cache
composer install --no-dev --optimize-autoloader
php artisan view:clear
php artisan config:clear
php artisan migrate --seed --force
chown -R www-data:www-data /var/www/pterodactyl/*
php artisan queue:restart
curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
apt update
apt install -y nodejs
npm i -g yarn
yarn
yarn build:production
sudo php artisan optimize:clear
php artisan up
}
while true; do
read -p "Are you sure that you want to repair the panel [y/N]? " yn
case $yn in
[Yy]* ) repairPanel; break;;
[Nn]* ) exit;;
* ) exit;;
esac
done

View File

@ -0,0 +1,268 @@
:root {
--main-color: #0D181E;
--secundary-color: #132537;
--tertiary-color: #0a354d;
--bacground-url: url("https://i.imgur.com/u6HYFAY.png");
}
html {
background-image: var(--bacground-url);
background-attachment: fixed;
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
background-color: transparent;
}
a.GreyRowBox-sc-1xo9c6v-0.ServerRow__StatusIndicatorBox-sc-1ibsw91-2.dyLna-D.fRwFrz.DashboardContainer___StyledServerRow-sc-1topkxf-2 {
background-color: var(--main-color) !important;
}
a.GreyRowBox-sc-1xo9c6v-0.ServerRow__StatusIndicatorBox-sc-1ibsw91-2.dyLna-D.fwbDSe.DashboardContainer___StyledServerRow-sc-1topkxf-2.jbVWLN {
background-color: var(--main-color) !important;
background-size: cover;
}
div.SubNavigation-sc-lfuaoi-0 {
background-color: rgba(255, 255, 255, 0) !important;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1) !important;
}
div.grid.grid-cols-6.gap-2.md:gap-4.col-span-4.lg:col-span-1.order-last.lg:order-none {
background-color: var(--main-color);
}
div.style-module_2Vp6MaXq.bg-gray-600.cursor-pointer {
background: rgba(255, 255, 255, 0);
border-radius: 16px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(9.2px);
-webkit-backdrop-filter: blur(9.2px);
}
div.style-module_2Vp6MaXq.bg-gray-600 {
background: rgba(255, 255, 255, 0);
border-radius: 16px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(9.2px);
-webkit-backdrop-filter: blur(9.2px);
}
div.style-module_2XbmHEcn.group {
background-color: var(--secundary-color);
}
div.w-full.bg-neutral-900.shadow-md.overflow-x-auto {
background-color: var(--main-color)
}
div.icon.mr-4 {
background-color: var(--secundary-color)
}
a.style-module_35MPv1CD.style-module_35MPv1CD.active {
background-color: var(--main-color);
}
.style-module_1WqkLT9X {
background-color: var(--main-color) !important;
}
.style-module_1WqkLT9X:hover {
background-color: var(--secundary-color) !important;
}
.style-module_35MPv1CD.active {
background-color: var(--main-color) !important;
}
.style-module_35MPv1CD.active:hover {
background-color: var(--secundary-color) !important;
}
div.GreyRowBox-sc-1xo9c6v-0.iTERJN.flex-wrap.md:flex-nowrap.mt-2 {
background-color: var(--secundary-color)
}
div.TitledGreyBox___StyledDiv3-sc-gvsoy-4.fKIIIQ {
background-color: var(--main-color);
}
input.Input-sc-19rce1w-0.jqTCDz.cursor-pointer {
background-color: var(--secundary-color);
}
input.Input-sc-19rce1w-0.jqTCDz {
background-color: var(--secundary-color);
}
div.grid.grid-cols-10.py-4.border-b-2.border-gray-800.last:rounded-b.last:border-0.group {
background-color: var(--secundary-color);
}
div.TitledGreyBox___StyledDiv2-sc-gvsoy-1.jRrWLs {
background-color: var(--secundary-color);
}
div.ContentBox___StyledDiv-sc-mjlt6f-2.iGOcRf {
background-color: var(--secundary-color);
}
div.Modal___StyledDiv2-sc-9vzni8-3.ekHIsr {
background-color: var(--secundary-color)
}
div.GreyRowBox-sc-1xo9c6v-0.DatabaseRow___StyledGreyRowBox-sc-1t67zwr-13.iTERJN.gkSIus {
background-color: var(--secundary-color);
}
div.EditScheduleModal___StyledDiv2-sc-wh9db9-4.fhEpAC {
background-color: var(--secundary-color);
}
div.EditScheduleModal___StyledDiv4-sc-wh9db9-6.jyDDEO {
background-color: var(--secundary-color);
}
div.EditScheduleModal___StyledDiv5-sc-wh9db9-7.ueIjC {
background-color: var(--secundary-color);
}
a.GreyRowBox-sc-1xo9c6v-0.ScheduleContainer___StyledGreyRowBox-sc-dlqnx9-2.dyLna-D.bppajE {
background-color: var(--secundary-color);
}
div.GreyRowBox-sc-1xo9c6v-0.UserRow___StyledGreyRowBox-sc-hg2wjz-0.dyLna-D.dmlaEn {
background-color: var(--secundary-color);
}
div.CreateBackupButton___StyledDiv2-sc-da8bqw-3.eDncUf {
background-color: var(--secundary-color);
}
textarea.Input__Textarea-sc-19rce1w-1.kKFWRA {
background-color: var(--secundary-color);
}
div.flex.justify-end.space-x-4.mt-4.w-full.md:mt-0.md:w-48 {
background-color: var(--secundary-color);
}
select.Select-sc-17exaqp-0.dupyoa {
background-color: var(--main-color);
}
div.TitledGreyBox___StyledDiv-sc-gvsoy-0.oLbNP.StartupContainer___StyledTitledGreyBox-sc-163imy2-1.kRunTE {
background-color: var(--secundary-color);
}
a.GreyRowBox-sc-1xo9c6v-0.ServerRow__StatusIndicatorBox-sc-1ibsw91-2.dyLna-D {
background-color: var(--main-color)
}
label.PermissionRow__Container-sc-1h899cn-0.icxFlO:hover {
background-color: var(--tertiary-color);
}
div.style-module_1DtraXMW.bg-gray-700 {
background-color: var(--main-color);
}
input.Input-sc-19rce1w-0.jqTCDz {
background-color: var(--secundary-color);
}
div.TitledGreyBox___StyledDiv-sc-gvsoy-0.oLbNP {
background-color: var(--main-color);
}
div.grid.grid-cols-10.py-4.border-b-2.border-gray-800.last:rounded-b.last:border-0.group {
background-color: var(--main-color);
}
.group {
background-color: var(--main-color);
}
.GreyRowBox-sc-1xo9c6v-0 {
background-color: var(--main-color);
}
#app {
background-image: var(--bacground-url);
background-attachment: fixed;
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
background-color: transparent;
}
/*
Server Console style module
*/
div.server-console-style-module__stat_block {
background: rgba(255, 255, 255, 0);
border-radius: 16px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(9.2px);
-webkit-backdrop-filter: blur(9.2px);
}
div.server-console-style-module__icon.bg-gray-700 {
background-color: var(--secundary-color);
}
button.style-module_4LBM1DKx {
/* From https://css.glass */
background: rgba(255, 255, 255, 0);
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(8.6px);
-webkit-backdrop-filter: blur(8.6px);
}
div.server-console-style-module__chart_container {
background: rgba(255, 255, 255, 0);
border-radius: 16px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(9.2px);
-webkit-backdrop-filter: blur(9.2px);
}
button.style-module_4LBM1DKx.style-module_3kBDV_wo.style-module_Yp7-2Fw-.flex-1:hover {
background-color: var(--main-color);
}
input.Input-sc-19rce1w-0.ZkNLd {
background-color: var(--main-color);
}
input.Input-sc-19rce1w-0.jqTCDz {
background-color: var(--secundary-color);
;
}
body {
overflow: overlay;
}
Input {
background-color: var(--secundary-color) !important;
}
select {
background-color: var(--secundary-color) !important;
}
select {
background-color: var(--secundary-color) !important;
}
p.StartupContainer___StyledP-sc-163imy2-3.ekbHAG {
background-color: var(--secundary-color) !important;
}

View File

@ -0,0 +1,224 @@
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { ITerminalOptions, Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
import { SearchAddon } from 'xterm-addon-search';
import { SearchBarAddon } from 'xterm-addon-search-bar';
import { WebLinksAddon } from 'xterm-addon-web-links';
import { ScrollDownHelperAddon } from '@/plugins/XtermScrollDownHelperAddon';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
import { ServerContext } from '@/state/server';
import { usePermissions } from '@/plugins/usePermissions';
import { theme as th } from 'twin.macro';
import useEventListener from '@/plugins/useEventListener';
import { debounce } from 'debounce';
import { usePersistedState } from '@/plugins/usePersistedState';
import { SocketEvent, SocketRequest } from '@/components/server/events';
import classNames from 'classnames';
import { ChevronDoubleRightIcon } from '@heroicons/react/solid';
import 'xterm/css/xterm.css';
import styles from './style.module.css';
const theme = {
background: '#111F26',
cursor: 'transparent',
black: th`colors.black`.toString(),
red: '#E54B4B',
green: '#9ECE58',
yellow: '#FAED70',
blue: '#396FE2',
magenta: '#BB80B3',
cyan: '#2DDAFD',
white: '#d0d0d0',
brightBlack: 'rgba(255, 255, 255, 0.2)',
brightRed: '#FF5370',
brightGreen: '#C3E88D',
brightYellow: '#FFCB6B',
brightBlue: '#82AAFF',
brightMagenta: '#C792EA',
brightCyan: '#89DDFF',
brightWhite: '#ffffff',
selection: '#FAF089',
};
const terminalProps: ITerminalOptions = {
disableStdin: true,
cursorStyle: 'underline',
allowTransparency: true,
fontSize: 12,
fontFamily: th('fontFamily.mono'),
rows: 30,
theme: theme,
};
export default () => {
const TERMINAL_PRELUDE = '\u001b[1m\u001b[33mcontainer@pterodactyl~ \u001b[0m';
const ref = useRef<HTMLDivElement>(null);
const terminal = useMemo(() => new Terminal({ ...terminalProps }), []);
const fitAddon = new FitAddon();
const searchAddon = new SearchAddon();
const searchBar = new SearchBarAddon({ searchAddon });
const webLinksAddon = new WebLinksAddon();
const scrollDownHelperAddon = new ScrollDownHelperAddon();
const { connected, instance } = ServerContext.useStoreState((state) => state.socket);
const [canSendCommands] = usePermissions(['control.console']);
const serverId = ServerContext.useStoreState((state) => state.server.data!.id);
const isTransferring = ServerContext.useStoreState((state) => state.server.data!.isTransferring);
const [history, setHistory] = usePersistedState<string[]>(`${serverId}:command_history`, []);
const [historyIndex, setHistoryIndex] = useState(-1);
const handleConsoleOutput = (line: string, prelude = false) =>
terminal.writeln((prelude ? TERMINAL_PRELUDE : '') + line.replace(/(?:\r\n|\r|\n)$/im, '') + '\u001b[0m');
const handleTransferStatus = (status: string) => {
switch (status) {
// Sent by either the source or target node if a failure occurs.
case 'failure':
terminal.writeln(TERMINAL_PRELUDE + 'Transfer has failed.\u001b[0m');
return;
// Sent by the source node whenever the server was archived successfully.
case 'archive':
terminal.writeln(
TERMINAL_PRELUDE + 'Server has been archived successfully, attempting connection to target node..\u001b[0m'
);
}
};
const handleDaemonErrorOutput = (line: string) =>
terminal.writeln(TERMINAL_PRELUDE + '\u001b[1m\u001b[41m' + line.replace(/(?:\r\n|\r|\n)$/im, '') + '\u001b[0m');
const handlePowerChangeEvent = (state: string) =>
terminal.writeln(TERMINAL_PRELUDE + 'Server marked as ' + state + '...\u001b[0m');
const handleCommandKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'ArrowUp') {
const newIndex = Math.min(historyIndex + 1, history!.length - 1);
setHistoryIndex(newIndex);
e.currentTarget.value = history![newIndex] || '';
// By default up arrow will also bring the cursor to the start of the line,
// so we'll preventDefault to keep it at the end.
e.preventDefault();
}
if (e.key === 'ArrowDown') {
const newIndex = Math.max(historyIndex - 1, -1);
setHistoryIndex(newIndex);
e.currentTarget.value = history![newIndex] || '';
}
const command = e.currentTarget.value;
if (e.key === 'Enter' && command.length > 0) {
setHistory((prevHistory) => [command, ...prevHistory!].slice(0, 32));
setHistoryIndex(-1);
instance && instance.send('send command', command);
e.currentTarget.value = '';
}
};
useEffect(() => {
if (connected && ref.current && !terminal.element) {
terminal.loadAddon(fitAddon);
terminal.loadAddon(searchAddon);
terminal.loadAddon(searchBar);
terminal.loadAddon(webLinksAddon);
terminal.loadAddon(scrollDownHelperAddon);
terminal.open(ref.current);
fitAddon.fit();
// Add support for capturing keys
terminal.attachCustomKeyEventHandler((e: KeyboardEvent) => {
if ((e.ctrlKey || e.metaKey) && e.key === 'c') {
document.execCommand('copy');
return false;
} else if ((e.ctrlKey || e.metaKey) && e.key === 'f') {
e.preventDefault();
searchBar.show();
return false;
} else if (e.key === 'Escape') {
searchBar.hidden();
}
return true;
});
}
}, [terminal, connected]);
useEventListener(
'resize',
debounce(() => {
if (terminal.element) {
fitAddon.fit();
}
}, 100)
);
useEffect(() => {
const listeners: Record<string, (s: string) => void> = {
[SocketEvent.STATUS]: handlePowerChangeEvent,
[SocketEvent.CONSOLE_OUTPUT]: handleConsoleOutput,
[SocketEvent.INSTALL_OUTPUT]: handleConsoleOutput,
[SocketEvent.TRANSFER_LOGS]: handleConsoleOutput,
[SocketEvent.TRANSFER_STATUS]: handleTransferStatus,
[SocketEvent.DAEMON_MESSAGE]: (line) => handleConsoleOutput(line, true),
[SocketEvent.DAEMON_ERROR]: handleDaemonErrorOutput,
};
if (connected && instance) {
// Do not clear the console if the server is being transferred.
if (!isTransferring) {
terminal.clear();
}
Object.keys(listeners).forEach((key: string) => {
instance.addListener(key, listeners[key]);
});
instance.send(SocketRequest.SEND_LOGS);
}
return () => {
if (instance) {
Object.keys(listeners).forEach((key: string) => {
instance.removeListener(key, listeners[key]);
});
}
};
}, [connected, instance]);
return (
<div className={classNames(styles.terminal, 'relative')}>
<SpinnerOverlay visible={!connected} size={'large'} />
<div className={classNames(styles.container, styles.overflows_container, { 'rounded-b': !canSendCommands })}>
<div className={'h-full'}>
<div id={styles.terminal} ref={ref} />
</div>
</div>
{canSendCommands && (
<div className={classNames('relative', styles.overflows_container)}>
<input
className={classNames('peer', styles.command_input)}
type={'text'}
placeholder={'Type a command...'}
aria-label={'Console command input.'}
disabled={!instance || !connected}
onKeyDown={handleCommandKeyDown}
autoCorrect={'off'}
autoCapitalize={'none'}
/>
<div
className={classNames(
'text-gray-100 peer-focus:text-gray-50 peer-focus:animate-pulse',
styles.command_icon
)}
>
<ChevronDoubleRightIcon className={'w-4 h-4'} />
</div>
</div>
)}
</div>
);
};

View File

@ -0,0 +1,17 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from '@/components/App';
import { setConfig } from 'react-hot-loader';
import './IceMinecraftTheme.css';
// Enable language support.
import './i18n';
// Prevents page reloads while making component changes which
// also avoids triggering constant loading indicators all over
// the place in development.
//
// @see https://github.com/gaearon/react-hot-loader#hook-support
setConfig({ reloadHooks: false });
ReactDOM.render(<App />, document.getElementById('app'));