fix(workflow): Vagrant stupid no more + Auto Linting :3

This commit is contained in:
Why Context
2025-05-02 19:13:59 +01:00
committed by Naterfute
parent 8eb40545b0
commit 92243577df
6 changed files with 214 additions and 231 deletions

20
Vagrantfile vendored
View File

@@ -7,10 +7,24 @@ Vagrant.configure("2") do |config|
config.vm.provider "virtualbox" do |vb|
vb.memory = "4096"
vb.cpus = "4"
vb.cpuexecutioncap = 95
vb.customize ["modifyvm", :id, "--nictype1", "virtio"]
vb.customize ["modifyvm", :id, "--nictype2", "virtio"]
vb.customize ["storagectl", :id, "--name", "IDE Controller", "--remove"]
vb.customize ["storagectl", :id, "--name", "SATA Controller", "--add", "sata"]
vb.customize ["modifyvm", :id, "--boot1", "disk"]
vb.customize ["modifyvm", :id, "--nic1", "nat"]
end
config.vm.provider "vmware_desktop" do |v|
v.vmx["memsize"] = "4096"
v.vmx["numvcpus"] = "4"
v.vmx["tools.upgrade.policy"] = "manual"
v.vmx["RemoteDisplay.vnc.enabled"] = "FALSE"
v.vmx["vhv.enable"] = "FALSE"
v.vmx["ethernet0.connectionType"] = "nat"
v.vmx["ethernet0.wakeOnPacketTx"] = "TRUE"
v.vmx["ethernet0.addressType"] = "generated"
end
# Libvirt provider
config.vm.provider "libvirt" do |libvirt|
@@ -20,9 +34,9 @@ Vagrant.configure("2") do |config|
end
# setup the synced folder and provision the VM
config.vm.synced_folder ".", "/var/www/pterodactyl",
type: "nfs",
nfs_version: 4
config.vm.synced_folder ".", "/var/www/pterodactyl"
# type: "virtualbox"
# nfs_version: 4
config.vm.provision "shell", path: "vagrant/provision.sh"

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "pyrodactyl",
"version": "3.0.0",
"version": "4.0.0-dev",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "pyrodactyl",
"version": "3.0.0",
"version": "4.0.0-dev",
"dependencies": {
"@codemirror/autocomplete": "^6.16.0",
"@codemirror/commands": "^6.3.3",

View File

@@ -1,6 +1,6 @@
import * as React from 'react';
import { cn } from '@/lib/utils';
// import { cn } from '@/lib/utils';
const ModBox = React.forwardRef<React.ElementRef<'div'>, React.ComponentPropsWithoutRef<'div'>>(({ ...props }, ref) => {
return <div ref={ref} className='mb-4 w-full text-nowrap select-none' {...props}></div>;

View File

@@ -1,245 +1,214 @@
import { hashToPath } from "@/helpers";
import { useVirtualizer } from "@tanstack/react-virtual";
import debounce from "debounce";
import { For } from "million/react";
import { useEffect, useRef, useState } from "react";
import { useLocation } from "react-router-dom";
import { hashToPath } from '@/helpers';
import { useVirtualizer } from '@tanstack/react-virtual';
import debounce from 'debounce';
import { For } from 'million/react';
import { useEffect, useRef, useState } from 'react';
import { useLocation } from 'react-router-dom';
import Can from "@/components/elements/Can";
import { Checkbox } from "@/components/elements/CheckboxNew";
import ErrorBoundary from "@/components/elements/ErrorBoundary";
import { MainPageHeader } from "@/components/elements/MainPageHeader";
import { ServerError } from "@/components/elements/ScreenBlock";
import ServerContentBlock from "@/components/elements/ServerContentBlock";
import FileManagerBreadcrumbs from "@/components/server/files/FileManagerBreadcrumbs";
import FileManagerStatus from "@/components/server/files/FileManagerStatus";
import FileObjectRow from "@/components/server/files/FileObjectRow";
import MassActionsBar from "@/components/server/files/MassActionsBar";
import NewDirectoryButton from "@/components/server/files/NewDirectoryButton";
import UploadButton from "@/components/server/files/UploadButton";
import Can from '@/components/elements/Can';
import { Checkbox } from '@/components/elements/CheckboxNew';
import ErrorBoundary from '@/components/elements/ErrorBoundary';
import { MainPageHeader } from '@/components/elements/MainPageHeader';
import { ServerError } from '@/components/elements/ScreenBlock';
import ServerContentBlock from '@/components/elements/ServerContentBlock';
import FileManagerBreadcrumbs from '@/components/server/files/FileManagerBreadcrumbs';
import FileManagerStatus from '@/components/server/files/FileManagerStatus';
import FileObjectRow from '@/components/server/files/FileObjectRow';
import MassActionsBar from '@/components/server/files/MassActionsBar';
import NewDirectoryButton from '@/components/server/files/NewDirectoryButton';
import UploadButton from '@/components/server/files/UploadButton';
import { httpErrorToHuman } from "@/api/http";
import { FileObject } from "@/api/server/files/loadDirectory";
import { httpErrorToHuman } from '@/api/http';
import { FileObject } from '@/api/server/files/loadDirectory';
import { useStoreActions } from "@/state/hooks";
import { ServerContext } from "@/state/server";
import { useStoreActions } from '@/state/hooks';
import { ServerContext } from '@/state/server';
import useFileManagerSwr from "@/plugins/useFileManagerSwr";
import useFileManagerSwr from '@/plugins/useFileManagerSwr';
import NewFileButton from "./NewFileButton";
import NewFileButton from './NewFileButton';
const sortFiles = (files: FileObject[]): FileObject[] => {
const sortedFiles: FileObject[] = files
.sort((a, b) => a.name.localeCompare(b.name))
.sort((a, b) => (a.isFile === b.isFile ? 0 : a.isFile ? 1 : -1));
return sortedFiles.filter(
(file, index) => index === 0 || file.name !== sortedFiles[index - 1]?.name,
);
const sortedFiles: FileObject[] = files
.sort((a, b) => a.name.localeCompare(b.name))
.sort((a, b) => (a.isFile === b.isFile ? 0 : a.isFile ? 1 : -1));
return sortedFiles.filter((file, index) => index === 0 || file.name !== sortedFiles[index - 1]?.name);
};
export default () => {
const parentRef = useRef<HTMLDivElement | null>(null);
const parentRef = useRef<HTMLDivElement | null>(null);
const id = ServerContext.useStoreState((state) => state.server.data!.id);
const { hash, pathname } = useLocation();
const { data: files, error, mutate } = useFileManagerSwr();
const id = ServerContext.useStoreState((state) => state.server.data!.id);
const { hash, pathname } = useLocation();
const { data: files, error, mutate } = useFileManagerSwr();
const directory = ServerContext.useStoreState(
(state) => state.files.directory,
);
const clearFlashes = useStoreActions(
(actions) => actions.flashes.clearFlashes,
);
const setDirectory = ServerContext.useStoreActions(
(actions) => actions.files.setDirectory,
);
const directory = ServerContext.useStoreState((state) => state.files.directory);
const clearFlashes = useStoreActions((actions) => actions.flashes.clearFlashes);
const setDirectory = ServerContext.useStoreActions((actions) => actions.files.setDirectory);
const setSelectedFiles = ServerContext.useStoreActions(
(actions) => actions.files.setSelectedFiles,
);
const selectedFilesLength = ServerContext.useStoreState(
(state) => state.files.selectedFiles.length,
);
const setSelectedFiles = ServerContext.useStoreActions((actions) => actions.files.setSelectedFiles);
const selectedFilesLength = ServerContext.useStoreState((state) => state.files.selectedFiles.length);
const searchInputRef = useRef<HTMLInputElement>(null);
const searchInputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
clearFlashes("files");
setSelectedFiles([]);
setDirectory(hashToPath(hash));
}, [hash]);
useEffect(() => {
clearFlashes('files');
setSelectedFiles([]);
setDirectory(hashToPath(hash));
}, [hash]);
useEffect(() => {
mutate();
}, [directory]);
useEffect(() => {
mutate();
}, [directory]);
const onSelectAllClick = () => {
console.log("files", files);
setSelectedFiles(
selectedFilesLength === (files?.length === 0 ? -1 : files?.length)
? []
: files?.map((file) => file.name) || [],
const onSelectAllClick = () => {
console.log('files', files);
setSelectedFiles(
selectedFilesLength === (files?.length === 0 ? -1 : files?.length)
? []
: files?.map((file) => file.name) || [],
);
};
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearchTerm = debounce(setSearchTerm, 50);
const filesArray = sortFiles(files ?? []).filter((file) =>
file.name.toLowerCase().includes(searchTerm.toLowerCase()),
);
};
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = debounce(setSearchTerm, 50);
useEffect(() => {
setSearchTerm('');
const filesArray = sortFiles(files ?? []).filter((file) =>
file.name.toLowerCase().includes(searchTerm.toLowerCase()),
);
// Clean imput using a reference
if (searchInputRef.current) {
searchInputRef.current.value = '';
}
}, [hash, pathname, directory]);
useEffect(() => {
setSearchTerm("");
// Clean imput using a reference
if (searchInputRef.current) {
searchInputRef.current.value = "";
if (error) {
return <ServerError title={'Something went wrong.'} message={httpErrorToHuman(error)} />;
}
}, [hash, pathname, directory]);
if (error) {
const rowVirtualizer = useVirtualizer({
// count: 10000,
count: filesArray.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 54,
// scrollMargin: 54,
});
return (
<ServerError
title={"Something went wrong."}
message={httpErrorToHuman(error)}
/>
<ServerContentBlock className='!p-0' title={'File Manager'} showFlashKey={'files'}>
<div className='px-2 sm:px-14 pt-2 sm:pt-14'>
<ErrorBoundary>
<MainPageHeader title={'Files'}>
<Can action={'file.create'}>
<div className='flex flex-row gap-1'>
<FileManagerStatus />
<NewDirectoryButton />
<NewFileButton id={id} />
<UploadButton />
</div>
</Can>
</MainPageHeader>
<div className={'flex flex-wrap-reverse md:flex-nowrap mb-4'}>
<FileManagerBreadcrumbs
renderLeft={
<Checkbox
className='ml-[1.22rem] mr-4'
checked={selectedFilesLength === (files?.length === 0 ? -1 : files?.length)}
onCheckedChange={() => onSelectAllClick()}
/>
}
/>
</div>
</ErrorBoundary>
</div>
{!files ? null : (
<>
{!files.length ? (
<p className={`text-sm text-zinc-400 text-center`}>This folder is empty.</p>
) : (
<>
<div ref={parentRef} style={{ height: `calc(100vh - 194px)`, overflowY: 'scroll' }}>
<div
data-pyro-file-manager-files
style={{
background:
'radial-gradient(124.75% 124.75% at 50.01% -10.55%, rgb(16, 16, 16) 0%, rgb(4, 4, 4) 100%)',
}}
className='p-1 border-[1px] border-[#ffffff12] rounded-xl ml-14 mr-12'
>
<div className='relative w-full h-full mb-1'>
<svg
xmlns='http://www.w3.org/2000/svg'
fill='none'
viewBox='0 0 24 24'
strokeWidth={1.5}
stroke='currentColor'
className='w-5 h-5 absolute top-1/2 -translate-y-1/2 left-5 opacity-40'
>
<path
strokeLinecap='round'
strokeLinejoin='round'
d='m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z'
/>
</svg>
<input
ref={searchInputRef}
className='pl-14 py-4 w-full rounded-lg bg-[#ffffff11] text-sm font-bold'
type='text'
placeholder='Search...'
onChange={(event) => debouncedSearchTerm(event.target.value)}
/>
</div>
<For
each={rowVirtualizer.getVirtualItems()}
style={{
height: `${rowVirtualizer.getTotalSize()}px`,
width: '100%',
overflow: 'hidden',
borderRadius: '0.5rem',
position: 'relative',
}}
as='div'
memo
>
{(virtualItem) => {
if (filesArray[virtualItem.index] !== undefined) {
return (
<div
key={virtualItem.key}
style={{
position: 'absolute',
top: 0,
left: 0,
height: `${virtualItem.size}px`,
width: '100%',
paddingBottom: '1px',
transform: `translateY(${virtualItem.start}px)`,
}}
>
<FileObjectRow
// @ts-ignore
file={filesArray[virtualItem.index]}
key={filesArray[virtualItem.index]?.name}
/>
</div>
);
}
return <></>;
}}
</For>
</div>
</div>
<MassActionsBar />
</>
)}
</>
)}
</ServerContentBlock>
);
}
const rowVirtualizer = useVirtualizer({
// count: 10000,
count: filesArray.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 54,
// scrollMargin: 54,
});
return (
<ServerContentBlock
className="!p-0"
title={"File Manager"}
showFlashKey={"files"}
>
<div className="px-2 sm:px-14 pt-2 sm:pt-14">
<ErrorBoundary>
<MainPageHeader title={"Files"}>
<Can action={"file.create"}>
<div className="flex flex-row gap-1">
<FileManagerStatus />
<NewDirectoryButton />
<NewFileButton id={id} />
<UploadButton />
</div>
</Can>
</MainPageHeader>
<div className={"flex flex-wrap-reverse md:flex-nowrap mb-4"}>
<FileManagerBreadcrumbs
renderLeft={
<Checkbox
className="ml-[1.22rem] mr-4"
checked={
selectedFilesLength ===
(files?.length === 0 ? -1 : files?.length)
}
onCheckedChange={() => onSelectAllClick()}
/>
}
/>
</div>
</ErrorBoundary>
</div>
{!files ? null : (
<>
{!files.length ? (
<p className={`text-sm text-zinc-400 text-center`}>
This folder is empty.
</p>
) : (
<>
<div
ref={parentRef}
style={{ height: `calc(100vh - 194px)`, overflowY: "scroll" }}
>
<div
data-pyro-file-manager-files
style={{
background:
"radial-gradient(124.75% 124.75% at 50.01% -10.55%, rgb(16, 16, 16) 0%, rgb(4, 4, 4) 100%)",
}}
className="p-1 border-[1px] border-[#ffffff12] rounded-xl ml-14 mr-12"
>
<div className="relative w-full h-full mb-1">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-5 h-5 absolute top-1/2 -translate-y-1/2 left-5 opacity-40"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"
/>
</svg>
<input
ref={searchInputRef}
className="pl-14 py-4 w-full rounded-lg bg-[#ffffff11] text-sm font-bold"
type="text"
placeholder="Search..."
onChange={(event) =>
debouncedSearchTerm(event.target.value)
}
/>
</div>
<For
each={rowVirtualizer.getVirtualItems()}
style={{
height: `${rowVirtualizer.getTotalSize()}px`,
width: "100%",
overflow: "hidden",
borderRadius: "0.5rem",
position: "relative",
}}
as="div"
memo
>
{(virtualItem) => {
if (filesArray[virtualItem.index] !== undefined) {
return (
<div
key={virtualItem.key}
style={{
position: "absolute",
top: 0,
left: 0,
height: `${virtualItem.size}px`,
width: "100%",
paddingBottom: "1px",
transform: `translateY(${virtualItem.start}px)`,
}}
>
<FileObjectRow
// @ts-ignore
file={filesArray[virtualItem.index]}
key={filesArray[virtualItem.index]?.name}
/>
</div>
);
}
return <></>;
}}
</For>
</div>
</div>
<MassActionsBar />
</>
)}
</>
)}
</ServerContentBlock>
);
};

View File

@@ -1,8 +1,8 @@
import { useEffect, useMemo, useState } from 'react';
import { toast } from 'sonner';
import { ScrollMenu } from '@/components/server/modrinth/ScrollMenu';
import Checkbox from '@/components/elements/inputs/Checkbox';
import { ScrollMenu } from '@/components/server/modrinth/ScrollMenu';
import { apiEndpoints, fetchHeaders, persistent, settings } from './config';

View File

@@ -39,11 +39,11 @@ function formatObjectToIdentString(object: any, indentLevel: number = 0): string
if (isObject(object)) {
return getObjectKeys(object)
.map((key) => {
const value = object[key];
return `${indent}${key}: ${formatObjectToIdentString(value, indentLevel + 1)}`;
})
.join('\n');
.map((key) => {
const value = object[key];
return `${indent}${key}: ${formatObjectToIdentString(value, indentLevel + 1)}`;
})
.join('\n');
}
if (Array.isArray(object)) {