diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 0000000..fa31446
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,9 @@
+{
+ "printWidth": 120,
+ "tabWidth": 2,
+ "useTabs": false,
+ "semi": true,
+ "singleQuote": true,
+ "jsxSingleQuote": true,
+ "endOfLine": "lf"
+}
diff --git a/app/BlueprintFramework/Controllers/ExtensionConfigurationController.php b/app/BlueprintFramework/Controllers/ExtensionConfigurationController.php
index 76bd14c..d9e330b 100644
--- a/app/BlueprintFramework/Controllers/ExtensionConfigurationController.php
+++ b/app/BlueprintFramework/Controllers/ExtensionConfigurationController.php
@@ -20,7 +20,23 @@ class ExtensionConfigurationController extends Controller
*/
public function update(ExtensionConfigurationRequest $request): RedirectResponse
{
- foreach ($request->normalize() as $key => $value) { $this->settings->set('blueprint::extensionconfig_' . $key, $value); }
+ // set extension eggs to be -1 (Show all), then overwrite if needed
+ $this->settings->set('blueprint::extensionconfig_' . $request->input('_identifier', 'blueprint') . '_eggs', '["-1"]');
+
+ foreach ($request->normalize() as $key => $value) {
+ if (str_ends_with($key, '_eggs')) {
+ // if there are other eggs set, remove the -1 'egg'
+ $eggs = (array)$value['*'];
+ if (count($eggs) > 1 && in_array('-1', $eggs)) {
+ $eggs = array_diff($eggs, ['-1']);
+ }
+
+ $value = json_encode(array_values($eggs));
+ }
+
+ $this->settings->set('blueprint::extensionconfig_' . $key, $value);
+ }
+
return redirect()->route('admin.extensions.'.$request->input('_identifier', 'blueprint').'.index');
}
}
@@ -31,6 +47,8 @@ class ExtensionConfigurationRequest extends AdminFormRequest
return [
$this->input('_identifier', 'blueprint').'_adminlayouts' => 'boolean',
$this->input('_identifier', 'blueprint').'_dashboardwrapper' => 'boolean',
+ $this->input('_identifier', 'blueprint').'_eggs' => 'array',
+ $this->input('_identifier', 'blueprint').'_eggs.*' => 'numeric',
];
}
diff --git a/app/BlueprintFramework/Controllers/ExtensionRouteController.php b/app/BlueprintFramework/Controllers/ExtensionRouteController.php
new file mode 100644
index 0000000..4ed7a05
--- /dev/null
+++ b/app/BlueprintFramework/Controllers/ExtensionRouteController.php
@@ -0,0 +1,30 @@
+input('id', 'blueprint');
+ $eggs = $this->settings->get('blueprint::extensionconfig_' . $id . '_eggs');
+ return json_decode($eggs ?: '["-1"]');
+ }
+}
+
+class GetRouteEggsRequest extends ClientApiRequest {
+ public function authorize(): bool
+ {
+ return true;
+ }
+}
diff --git a/app/Http/Controllers/Admin/Extensions/Blueprint/BlueprintExtensionController.php b/app/Http/Controllers/Admin/Extensions/Blueprint/BlueprintExtensionController.php
index e4ab3bb..97ccfba 100644
--- a/app/Http/Controllers/Admin/Extensions/Blueprint/BlueprintExtensionController.php
+++ b/app/Http/Controllers/Admin/Extensions/Blueprint/BlueprintExtensionController.php
@@ -2,9 +2,9 @@
namespace Pterodactyl\Http\Controllers\Admin\Extensions\Blueprint;
+use Artisan;
use Illuminate\View\View;
use Illuminate\View\Factory as ViewFactory;
-use Artisan;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\BlueprintFramework\Services\PlaceholderService\BlueprintPlaceholderService;
use Pterodactyl\BlueprintFramework\Services\ConfigService\BlueprintConfigService;
diff --git a/blueprint/extensions/blueprint/private/build/extensions/controller.build b/blueprint/extensions/blueprint/private/build/extensions/controller.build
index 2b32eac..5937fe4 100644
--- a/blueprint/extensions/blueprint/private/build/extensions/controller.build
+++ b/blueprint/extensions/blueprint/private/build/extensions/controller.build
@@ -3,6 +3,7 @@
namespace Pterodactyl\Http\Controllers\Admin\Extensions\[id];
use Illuminate\View\View;
+use Pterodactyl\Models\Egg;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Helpers\SoftwareVersionService;
@@ -29,6 +30,7 @@ class [id]ExtensionController extends Controller
return $this->view->make('admin.extensions.[id].index', [
'blueprint' => $this->blueprint,
'version' => $this->version,
+ 'eggs' => Egg::all(),
'root' => $rootPath
]);
}
diff --git a/resources/scripts/api/server/getServer.ts b/resources/scripts/api/server/getServer.ts
index 860c423..a19493b 100644
--- a/resources/scripts/api/server/getServer.ts
+++ b/resources/scripts/api/server/getServer.ts
@@ -3,91 +3,94 @@ import { rawDataToServerAllocation, rawDataToServerEggVariable } from '@/api/tra
import { ServerEggVariable, ServerStatus } from '@/api/server/types';
export interface Allocation {
- id: number;
- ip: string;
- alias: string | null;
- port: number;
- notes: string | null;
- isDefault: boolean;
+ id: number;
+ ip: string;
+ alias: string | null;
+ port: number;
+ notes: string | null;
+ isDefault: boolean;
}
export interface Server {
- id: string;
- internalId: number | string;
- uuid: string;
- name: string;
- node: string;
- isNodeUnderMaintenance: boolean;
- status: ServerStatus;
- sftpDetails: {
- ip: string;
- port: number;
- };
- invocation: string;
- dockerImage: string;
- description: string;
- limits: {
- memory: number;
- swap: number;
- disk: number;
- io: number;
- cpu: number;
- threads: string;
- };
- eggFeatures: string[];
- featureLimits: {
- databases: number;
- allocations: number;
- backups: number;
- };
- isTransferring: boolean;
- variables: ServerEggVariable[];
- allocations: Allocation[];
-
- BlueprintFramework: {
- eggId: number;
- };
+ id: string;
+ internalId: number | string;
+ uuid: string;
+ name: string;
+ node: string;
+ isNodeUnderMaintenance: boolean;
+ status: ServerStatus;
+ sftpDetails: {
+ ip: string;
+ port: number;
+ };
+ invocation: string;
+ dockerImage: string;
+ description: string;
+ limits: {
+ memory: number;
+ swap: number;
+ disk: number;
+ io: number;
+ cpu: number;
+ threads: string;
+ };
+ eggFeatures: string[];
+ featureLimits: {
+ databases: number;
+ allocations: number;
+ backups: number;
+ };
+ isTransferring: boolean;
+ variables: ServerEggVariable[];
+ allocations: Allocation[];
+
+ BlueprintFramework: {
+ eggId: number;
+ };
}
export const rawDataToServerObject = ({ attributes: data }: FractalResponseData): Server => ({
- id: data.identifier,
- internalId: data.internal_id,
- uuid: data.uuid,
- name: data.name,
- node: data.node,
- isNodeUnderMaintenance: data.is_node_under_maintenance,
- status: data.status,
- invocation: data.invocation,
- dockerImage: data.docker_image,
- sftpDetails: {
- ip: data.sftp_details.ip,
- port: data.sftp_details.port,
- },
- description: data.description ? (data.description.length > 0 ? data.description : null) : null,
- limits: { ...data.limits },
- eggFeatures: data.egg_features || [],
- featureLimits: { ...data.feature_limits },
- isTransferring: data.is_transferring,
- variables: ((data.relationships?.variables as FractalResponseList | undefined)?.data || []).map(
- rawDataToServerEggVariable
- ),
- allocations: ((data.relationships?.allocations as FractalResponseList | undefined)?.data || []).map(
- rawDataToServerAllocation
- ),
+ id: data.identifier,
+ internalId: data.internal_id,
+ uuid: data.uuid,
+ name: data.name,
+ node: data.node,
+ isNodeUnderMaintenance: data.is_node_under_maintenance,
+ status: data.status,
+ invocation: data.invocation,
+ dockerImage: data.docker_image,
+ sftpDetails: {
+ ip: data.sftp_details.ip,
+ port: data.sftp_details.port,
+ },
+ description: data.description ? (data.description.length > 0 ? data.description : null) : null,
+ limits: { ...data.limits },
+ eggFeatures: data.egg_features || [],
+ featureLimits: { ...data.feature_limits },
+ isTransferring: data.is_transferring,
+ variables: ((data.relationships?.variables as FractalResponseList | undefined)?.data || []).map(
+ rawDataToServerEggVariable
+ ),
+ allocations: ((data.relationships?.allocations as FractalResponseList | undefined)?.data || []).map(
+ rawDataToServerAllocation
+ ),
- BlueprintFramework: { ...data.BlueprintFramework }
+ BlueprintFramework: {
+ eggId: data.BlueprintFramework.egg_id,
+ },
});
export default (uuid: string): Promise<[Server, string[]]> => {
- return new Promise((resolve, reject) => {
- http.get(`/api/client/servers/${uuid}`)
- .then(({ data }) =>
- resolve([
- rawDataToServerObject(data),
- // eslint-disable-next-line camelcase
- data.meta?.is_server_owner ? ['*'] : data.meta?.user_permissions || [],
- ])
- )
- .catch(reject);
- });
+ return new Promise((resolve, reject) => {
+ http
+ .get(`/api/client/servers/${uuid}`)
+ .then(({ data }) =>
+ resolve([
+ rawDataToServerObject(data),
+ // eslint-disable-next-line camelcase
+ data.meta?.is_server_owner ? ['*'] : data.meta?.user_permissions || [],
+ ])
+ )
+ .catch(reject);
+ });
};
diff --git a/resources/scripts/blueprint/extends/routers/ServerRouter.tsx b/resources/scripts/blueprint/extends/routers/ServerRouter.tsx
index 4114d16..d1d22ad 100644
--- a/resources/scripts/blueprint/extends/routers/ServerRouter.tsx
+++ b/resources/scripts/blueprint/extends/routers/ServerRouter.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useState, useEffect } from 'react';
import { NavLink, Route, Switch, useRouteMatch } from 'react-router-dom';
import TransitionRouter from '@/TransitionRouter';
import PermissionRoute from '@/components/elements/PermissionRoute';
@@ -12,6 +12,30 @@ import { ServerContext } from '@/state/server';
import routes from '@/routers/routes';
import blueprintRoutes from './routes';
+const blueprintExtensions = [...new Set(blueprintRoutes.server.map((route) => route.identifier))];
+
+/**
+ * Get the route egg IDs for each extension with server routes.
+ */
+const useExtensionEggs = () => {
+ const [extensionEggs, setExtensionEggs] = useState<{ [x: string]: string[] }>(
+ blueprintExtensions.reduce((prev, current) => ({ ...prev, [current]: ['-1'] }), {})
+ );
+
+ useEffect(() => {
+ (async () => {
+ const newEggs: { [x: string]: string[] } = {};
+ for (const id of blueprintExtensions) {
+ const resp = await fetch(`/api/client/extensions/blueprint/eggs?${new URLSearchParams({ id })}`);
+ newEggs[id] = (await resp.json()) as string[];
+ }
+ setExtensionEggs(newEggs);
+ })();
+ }, []);
+
+ return extensionEggs;
+};
+
export const NavigationLinks = () => {
const rootAdmin = useStoreState((state) => state.user.data!.rootAdmin);
const serverEgg = ServerContext.useStoreState((state) => state.server.data?.BlueprintFramework.eggId);
@@ -22,10 +46,11 @@ export const NavigationLinks = () => {
}
return `${(url ? match.url : match.path).replace(/\/*$/, '')}/${value.replace(/^\/+/, '')}`;
};
+ const extensionEggs = useExtensionEggs();
+ console.log(serverEgg);
return (
<>
-
{/* Pterodactyl routes */}
{routes.server
.filter((route) => !!route.name)
@@ -41,29 +66,31 @@ export const NavigationLinks = () => {
{route.name}
)
- )
- }
+ )}
{/* Blueprint routes */}
- {blueprintRoutes.server.length > 0 && blueprintRoutes.server
- .filter((route) => !!route.name)
- .filter((route) => route.adminOnly ? rootAdmin : true)
- .filter((route) => route.eggs && serverEgg ? route.eggs.includes(serverEgg) : true )
- .map((route) =>
- route.permission ? (
-
Allow this extension to extend the dashboard's blade wrapper.
+ +Guess
+