ui(admin): add "working" React admin ui
This commit is contained in:
parent
d1c7494933
commit
5402584508
199 changed files with 13387 additions and 151 deletions
12
resources/scripts/api/admin/databases/createDatabase.ts
Normal file
12
resources/scripts/api/admin/databases/createDatabase.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import http from '@/api/http';
|
||||
import { Database, rawDataToDatabase } from '@/api/admin/databases/getDatabases';
|
||||
|
||||
export default (name: string, host: string, port: number, username: string, password: string, include: string[] = []): Promise<Database> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post('/api/application/databases', {
|
||||
name, host, port, username, password,
|
||||
}, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToDatabase(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
9
resources/scripts/api/admin/databases/deleteDatabase.ts
Normal file
9
resources/scripts/api/admin/databases/deleteDatabase.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import http from '@/api/http';
|
||||
|
||||
export default (id: number): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.delete(`/api/application/databases/${id}`)
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
10
resources/scripts/api/admin/databases/getDatabase.ts
Normal file
10
resources/scripts/api/admin/databases/getDatabase.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import http from '@/api/http';
|
||||
import { Database, rawDataToDatabase } from '@/api/admin/databases/getDatabases';
|
||||
|
||||
export default (id: number, include: string[] = []): Promise<Database> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/application/databases/${id}`, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToDatabase(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
64
resources/scripts/api/admin/databases/getDatabases.ts
Normal file
64
resources/scripts/api/admin/databases/getDatabases.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
import http, { FractalResponseData, getPaginationSet, PaginatedResult } from '@/api/http';
|
||||
import { useContext } from 'react';
|
||||
import useSWR from 'swr';
|
||||
import { createContext } from '@/api/admin';
|
||||
|
||||
export interface Database {
|
||||
id: number;
|
||||
name: string;
|
||||
host: string;
|
||||
port: number;
|
||||
username: string;
|
||||
maxDatabases: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
getAddress (): string;
|
||||
}
|
||||
|
||||
export const rawDataToDatabase = ({ attributes }: FractalResponseData): Database => ({
|
||||
id: attributes.id,
|
||||
name: attributes.name,
|
||||
host: attributes.host,
|
||||
port: attributes.port,
|
||||
username: attributes.username,
|
||||
maxDatabases: attributes.max_databases,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
|
||||
getAddress: () => `${attributes.host}:${attributes.port}`,
|
||||
});
|
||||
|
||||
export interface Filters {
|
||||
id?: string;
|
||||
name?: string;
|
||||
host?: string;
|
||||
}
|
||||
|
||||
export const Context = createContext<Filters>();
|
||||
|
||||
export default (include: string[] = []) => {
|
||||
const { page, filters, sort, sortDirection } = useContext(Context);
|
||||
|
||||
const params = {};
|
||||
if (filters !== null) {
|
||||
Object.keys(filters).forEach(key => {
|
||||
// @ts-ignore
|
||||
params['filter[' + key + ']'] = filters[key];
|
||||
});
|
||||
}
|
||||
|
||||
if (sort !== null) {
|
||||
// @ts-ignore
|
||||
params.sort = (sortDirection ? '-' : '') + sort;
|
||||
}
|
||||
|
||||
return useSWR<PaginatedResult<Database>>([ 'databases', page, filters, sort, sortDirection ], async () => {
|
||||
const { data } = await http.get('/api/application/databases', { params: { include: include.join(','), page, ...params } });
|
||||
|
||||
return ({
|
||||
items: (data.data || []).map(rawDataToDatabase),
|
||||
pagination: getPaginationSet(data.meta.pagination),
|
||||
});
|
||||
});
|
||||
};
|
25
resources/scripts/api/admin/databases/searchDatabases.ts
Normal file
25
resources/scripts/api/admin/databases/searchDatabases.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import http from '@/api/http';
|
||||
import { Database, rawDataToDatabase } from '@/api/admin/databases/getDatabases';
|
||||
|
||||
interface Filters {
|
||||
name?: string;
|
||||
host?: string;
|
||||
}
|
||||
|
||||
export default (filters?: Filters): Promise<Database[]> => {
|
||||
const params = {};
|
||||
if (filters !== undefined) {
|
||||
Object.keys(filters).forEach(key => {
|
||||
// @ts-ignore
|
||||
params['filter[' + key + ']'] = filters[key];
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get('/api/application/databases', { params })
|
||||
.then(response => resolve(
|
||||
(response.data.data || []).map(rawDataToDatabase)
|
||||
))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
12
resources/scripts/api/admin/databases/updateDatabase.ts
Normal file
12
resources/scripts/api/admin/databases/updateDatabase.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import http from '@/api/http';
|
||||
import { Database, rawDataToDatabase } from '@/api/admin/databases/getDatabases';
|
||||
|
||||
export default (id: number, name: string, host: string, port: number, username: string, password: string | undefined, include: string[] = []): Promise<Database> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.patch(`/api/application/databases/${id}`, {
|
||||
name, host, port, username, password,
|
||||
}, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToDatabase(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
104
resources/scripts/api/admin/egg.ts
Normal file
104
resources/scripts/api/admin/egg.ts
Normal file
|
@ -0,0 +1,104 @@
|
|||
import type { AxiosError } from 'axios';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import type { SWRResponse } from 'swr';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import type { Model, UUID, WithRelationships } from '@/api/admin/index';
|
||||
import { withRelationships } from '@/api/admin/index';
|
||||
import type { Nest } from '@/api/admin/nest';
|
||||
import type { QueryBuilderParams } from '@/api/http';
|
||||
import http, { withQueryBuilderParams } from '@/api/http';
|
||||
import { Transformers } from '@definitions/admin';
|
||||
|
||||
export interface Egg extends Model {
|
||||
id: number;
|
||||
uuid: UUID;
|
||||
nestId: number;
|
||||
author: string;
|
||||
name: string;
|
||||
description: string | null;
|
||||
features: string[] | null;
|
||||
dockerImages: Record<string, string>;
|
||||
configFiles: Record<string, any> | null;
|
||||
configStartup: Record<string, any> | null;
|
||||
configStop: string | null;
|
||||
configFrom: number | null;
|
||||
startup: string;
|
||||
scriptContainer: string;
|
||||
copyScriptFrom: number | null;
|
||||
scriptEntry: string;
|
||||
scriptIsPrivileged: boolean;
|
||||
scriptInstall: string | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
relationships: {
|
||||
nest?: Nest;
|
||||
variables?: EggVariable[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface EggVariable extends Model {
|
||||
id: number;
|
||||
eggId: number;
|
||||
name: string;
|
||||
description: string;
|
||||
environmentVariable: string;
|
||||
defaultValue: string;
|
||||
isUserViewable: boolean;
|
||||
isUserEditable: boolean;
|
||||
// isRequired: boolean;
|
||||
rules: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* A standard API response with the minimum viable details for the frontend
|
||||
* to correctly render a egg.
|
||||
*/
|
||||
type LoadedEgg = WithRelationships<Egg, 'nest' | 'variables'>;
|
||||
|
||||
/**
|
||||
* Gets a single egg from the database and returns it.
|
||||
*/
|
||||
export const getEgg = async (id: number | string): Promise<LoadedEgg> => {
|
||||
const { data } = await http.get(`/api/application/eggs/${id}`, {
|
||||
params: {
|
||||
include: ['nest', 'variables'],
|
||||
},
|
||||
});
|
||||
|
||||
return withRelationships(Transformers.toEgg(data), 'nest', 'variables');
|
||||
};
|
||||
|
||||
export const searchEggs = async (
|
||||
nestId: number,
|
||||
params: QueryBuilderParams<'name'>,
|
||||
): Promise<WithRelationships<Egg, 'variables'>[]> => {
|
||||
const { data } = await http.get(`/api/application/nests/${nestId}/eggs`, {
|
||||
params: {
|
||||
...withQueryBuilderParams(params),
|
||||
include: ['variables'],
|
||||
},
|
||||
});
|
||||
|
||||
return data.data.map(Transformers.toEgg);
|
||||
};
|
||||
|
||||
export const exportEgg = async (eggId: number): Promise<Record<string, any>> => {
|
||||
const { data } = await http.get(`/api/application/eggs/${eggId}/export`);
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an SWR instance by automatically loading in the server for the currently
|
||||
* loaded route match in the admin area.
|
||||
*/
|
||||
export const useEggFromRoute = (): SWRResponse<LoadedEgg, AxiosError> => {
|
||||
const params = useParams<'id'>();
|
||||
|
||||
return useSWR(`/api/application/eggs/${params.id}`, async () => getEgg(Number(params.id)), {
|
||||
revalidateOnMount: false,
|
||||
revalidateOnFocus: false,
|
||||
});
|
||||
};
|
31
resources/scripts/api/admin/eggs/createEgg.ts
Normal file
31
resources/scripts/api/admin/eggs/createEgg.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import http from '@/api/http';
|
||||
import { Egg, rawDataToEgg } from '@/api/admin/eggs/getEgg';
|
||||
|
||||
type Egg2 = Omit<Omit<Partial<Egg>, 'configFiles'>, 'configStartup'> & { configFiles: string, configStartup: string };
|
||||
|
||||
export default (egg: Partial<Egg2>): Promise<Egg> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post(
|
||||
'/api/application/eggs',
|
||||
{
|
||||
nest_id: egg.nestId,
|
||||
name: egg.name,
|
||||
description: egg.description,
|
||||
features: egg.features,
|
||||
docker_images: egg.dockerImages,
|
||||
config_files: egg.configFiles,
|
||||
config_startup: egg.configStartup,
|
||||
config_stop: egg.configStop,
|
||||
config_from: egg.configFrom,
|
||||
startup: egg.startup,
|
||||
script_container: egg.scriptContainer,
|
||||
copy_script_from: egg.copyScriptFrom,
|
||||
script_entry: egg.scriptEntry,
|
||||
script_is_privileged: egg.scriptIsPrivileged,
|
||||
script_install: egg.scriptInstall,
|
||||
},
|
||||
)
|
||||
.then(({ data }) => resolve(rawDataToEgg(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
22
resources/scripts/api/admin/eggs/createEggVariable.ts
Normal file
22
resources/scripts/api/admin/eggs/createEggVariable.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import http from '@/api/http';
|
||||
import { EggVariable } from '@/api/admin/egg';
|
||||
import { Transformers } from '@definitions/admin';
|
||||
|
||||
export type CreateEggVariable = Omit<EggVariable, 'id' | 'eggId' | 'createdAt' | 'updatedAt' | 'relationships'>;
|
||||
|
||||
export default async (eggId: number, variable: CreateEggVariable): Promise<EggVariable> => {
|
||||
const { data } = await http.post(
|
||||
`/api/application/eggs/${eggId}/variables`,
|
||||
{
|
||||
name: variable.name,
|
||||
description: variable.description,
|
||||
env_variable: variable.environmentVariable,
|
||||
default_value: variable.defaultValue,
|
||||
user_viewable: variable.isUserViewable,
|
||||
user_editable: variable.isUserEditable,
|
||||
rules: variable.rules,
|
||||
},
|
||||
);
|
||||
|
||||
return Transformers.toEggVariable(data);
|
||||
};
|
9
resources/scripts/api/admin/eggs/deleteEgg.ts
Normal file
9
resources/scripts/api/admin/eggs/deleteEgg.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import http from '@/api/http';
|
||||
|
||||
export default (id: number): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.delete(`/api/application/eggs/${id}`)
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
9
resources/scripts/api/admin/eggs/deleteEggVariable.ts
Normal file
9
resources/scripts/api/admin/eggs/deleteEggVariable.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import http from '@/api/http';
|
||||
|
||||
export default (eggId: number, variableId: number): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.delete(`/api/application/eggs/${eggId}/variables/${variableId}`)
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
108
resources/scripts/api/admin/eggs/getEgg.ts
Normal file
108
resources/scripts/api/admin/eggs/getEgg.ts
Normal file
|
@ -0,0 +1,108 @@
|
|||
import { Nest } from '@/api/admin/nests/getNests';
|
||||
import { rawDataToServer, Server } from '@/api/admin/servers/getServers';
|
||||
import http, { FractalResponseData, FractalResponseList } from '@/api/http';
|
||||
import useSWR from 'swr';
|
||||
|
||||
export interface EggVariable {
|
||||
id: number;
|
||||
eggId: number;
|
||||
name: string;
|
||||
description: string;
|
||||
envVariable: string;
|
||||
defaultValue: string;
|
||||
userViewable: boolean;
|
||||
userEditable: boolean;
|
||||
rules: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export const rawDataToEggVariable = ({ attributes }: FractalResponseData): EggVariable => ({
|
||||
id: attributes.id,
|
||||
eggId: attributes.egg_id,
|
||||
name: attributes.name,
|
||||
description: attributes.description,
|
||||
envVariable: attributes.env_variable,
|
||||
defaultValue: attributes.default_value,
|
||||
userViewable: attributes.user_viewable,
|
||||
userEditable: attributes.user_editable,
|
||||
rules: attributes.rules,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
});
|
||||
|
||||
export interface Egg {
|
||||
id: number;
|
||||
uuid: string;
|
||||
nestId: number;
|
||||
author: string;
|
||||
name: string;
|
||||
description: string | null;
|
||||
features: string[] | null;
|
||||
dockerImages: Record<string, string>;
|
||||
configFiles: Record<string, any> | null;
|
||||
configStartup: Record<string, any> | null;
|
||||
configStop: string | null;
|
||||
configFrom: number | null;
|
||||
startup: string;
|
||||
scriptContainer: string;
|
||||
copyScriptFrom: number | null;
|
||||
scriptEntry: string;
|
||||
scriptIsPrivileged: boolean;
|
||||
scriptInstall: string | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
relations: {
|
||||
nest?: Nest;
|
||||
servers?: Server[];
|
||||
variables?: EggVariable[];
|
||||
};
|
||||
}
|
||||
|
||||
export const rawDataToEgg = ({ attributes }: FractalResponseData): Egg => ({
|
||||
id: attributes.id,
|
||||
uuid: attributes.uuid,
|
||||
nestId: attributes.nest_id,
|
||||
author: attributes.author,
|
||||
name: attributes.name,
|
||||
description: attributes.description,
|
||||
features: attributes.features,
|
||||
dockerImages: attributes.docker_images,
|
||||
configFiles: attributes.config?.files,
|
||||
configStartup: attributes.config?.startup,
|
||||
configStop: attributes.config?.stop,
|
||||
configFrom: attributes.config?.extends,
|
||||
startup: attributes.startup,
|
||||
copyScriptFrom: attributes.copy_script_from,
|
||||
scriptContainer: attributes.script?.container,
|
||||
scriptEntry: attributes.script?.entry,
|
||||
scriptIsPrivileged: attributes.script?.privileged,
|
||||
scriptInstall: attributes.script?.install,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
|
||||
relations: {
|
||||
nest: undefined,
|
||||
servers: ((attributes.relationships?.servers as FractalResponseList | undefined)?.data || []).map(
|
||||
rawDataToServer,
|
||||
),
|
||||
variables: ((attributes.relationships?.variables as FractalResponseList | undefined)?.data || []).map(
|
||||
rawDataToEggVariable,
|
||||
),
|
||||
},
|
||||
});
|
||||
|
||||
export const getEgg = async (id: number): Promise<Egg> => {
|
||||
const { data } = await http.get(`/api/application/eggs/${id}`, { params: { include: ['variables'] } });
|
||||
|
||||
return rawDataToEgg(data);
|
||||
};
|
||||
|
||||
export default (id: number) => {
|
||||
return useSWR<Egg>(`egg:${id}`, async () => {
|
||||
const { data } = await http.get(`/api/application/eggs/${id}`, { params: { include: ['variables'] } });
|
||||
|
||||
return rawDataToEgg(data);
|
||||
});
|
||||
};
|
31
resources/scripts/api/admin/eggs/updateEgg.ts
Normal file
31
resources/scripts/api/admin/eggs/updateEgg.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import http from '@/api/http';
|
||||
import { Egg, rawDataToEgg } from '@/api/admin/eggs/getEgg';
|
||||
|
||||
type Egg2 = Omit<Omit<Partial<Egg>, 'configFiles'>, 'configStartup'> & { configFiles?: string, configStartup?: string };
|
||||
|
||||
export default (id: number, egg: Partial<Egg2>): Promise<Egg> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.patch(
|
||||
`/api/application/eggs/${id}`,
|
||||
{
|
||||
nest_id: egg.nestId,
|
||||
name: egg.name,
|
||||
description: egg.description,
|
||||
features: egg.features,
|
||||
docker_images: egg.dockerImages,
|
||||
config_files: egg.configFiles,
|
||||
config_startup: egg.configStartup,
|
||||
config_stop: egg.configStop,
|
||||
config_from: egg.configFrom,
|
||||
startup: egg.startup,
|
||||
script_container: egg.scriptContainer,
|
||||
copy_script_from: egg.copyScriptFrom,
|
||||
script_entry: egg.scriptEntry,
|
||||
script_is_privileged: egg.scriptIsPrivileged,
|
||||
script_install: egg.scriptInstall,
|
||||
},
|
||||
)
|
||||
.then(({ data }) => resolve(rawDataToEgg(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
21
resources/scripts/api/admin/eggs/updateEggVariables.ts
Normal file
21
resources/scripts/api/admin/eggs/updateEggVariables.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import http from '@/api/http';
|
||||
import { EggVariable } from '@/api/admin/egg';
|
||||
import { Transformers } from '@definitions/admin';
|
||||
|
||||
export default async (eggId: number, variables: Omit<EggVariable, 'eggId' | 'createdAt' | 'updatedAt'>[]): Promise<EggVariable[]> => {
|
||||
const { data } = await http.patch(
|
||||
`/api/application/eggs/${eggId}/variables`,
|
||||
variables.map(variable => ({
|
||||
id: variable.id,
|
||||
name: variable.name,
|
||||
description: variable.description,
|
||||
env_variable: variable.environmentVariable,
|
||||
default_value: variable.defaultValue,
|
||||
user_viewable: variable.isUserViewable,
|
||||
user_editable: variable.isUserEditable,
|
||||
rules: variable.rules,
|
||||
})),
|
||||
);
|
||||
|
||||
return data.data.map(Transformers.toEggVariable);
|
||||
};
|
22
resources/scripts/api/admin/getVersion.ts
Normal file
22
resources/scripts/api/admin/getVersion.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import http from '@/api/http';
|
||||
|
||||
export interface VersionData {
|
||||
panel: {
|
||||
current: string;
|
||||
latest: string;
|
||||
}
|
||||
|
||||
wings: {
|
||||
latest: string;
|
||||
}
|
||||
|
||||
git: string | null;
|
||||
}
|
||||
|
||||
export default (): Promise<VersionData> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get('/api/application/version')
|
||||
.then(({ data }) => resolve(data))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
66
resources/scripts/api/admin/index.ts
Normal file
66
resources/scripts/api/admin/index.ts
Normal file
|
@ -0,0 +1,66 @@
|
|||
import { createContext } from 'react';
|
||||
|
||||
export interface Model {
|
||||
relationships: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export type UUID = string;
|
||||
|
||||
/**
|
||||
* Marks the provided relationships keys as present in the given model
|
||||
* rather than being optional to improve typing responses.
|
||||
*/
|
||||
export type WithRelationships<M extends Model, R extends string> = Omit<M, 'relationships'> & {
|
||||
relationships: Omit<M['relationships'], keyof R> & {
|
||||
[K in R]: NonNullable<M['relationships'][K]>;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper type that allows you to infer the type of an object by giving
|
||||
* it the specific API request function with a return type. For example:
|
||||
*
|
||||
* type EggT = InferModel<typeof getEgg>;
|
||||
*/
|
||||
export type InferModel<T extends (...args: any) => any> = ReturnType<T> extends Promise<infer U> ? U : T;
|
||||
|
||||
/**
|
||||
* Helper function that just returns the model you pass in, but types the model
|
||||
* such that TypeScript understands the relationships on it. This is just to help
|
||||
* reduce the amount of duplicated type casting all over the codebase.
|
||||
*/
|
||||
export const withRelationships = <M extends Model, R extends string> (model: M, ..._keys: R[]) => {
|
||||
return model as unknown as WithRelationships<M, R>;
|
||||
};
|
||||
|
||||
export interface ListContext<T> {
|
||||
page: number;
|
||||
setPage: (page: ((p: number) => number) | number) => void;
|
||||
|
||||
filters: T | null;
|
||||
setFilters: (filters: ((f: T | null) => T | null) | T | null) => void;
|
||||
|
||||
sort: string | null;
|
||||
setSort: (sort: string | null) => void;
|
||||
|
||||
sortDirection: boolean;
|
||||
setSortDirection: (direction: ((p: boolean) => boolean) | boolean) => void;
|
||||
}
|
||||
|
||||
function create<T> () {
|
||||
return createContext<ListContext<T>>({
|
||||
page: 1,
|
||||
setPage: () => 1,
|
||||
|
||||
filters: null,
|
||||
setFilters: () => null,
|
||||
|
||||
sort: null,
|
||||
setSort: () => null,
|
||||
|
||||
sortDirection: false,
|
||||
setSortDirection: () => false,
|
||||
});
|
||||
}
|
||||
|
||||
export { create as createContext };
|
13
resources/scripts/api/admin/location.ts
Normal file
13
resources/scripts/api/admin/location.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { Model } from '@/api/admin/index';
|
||||
import { Node } from '@/api/admin/node';
|
||||
|
||||
export interface Location extends Model {
|
||||
id: number;
|
||||
short: string;
|
||||
long: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
relationships: {
|
||||
nodes?: Node[];
|
||||
};
|
||||
}
|
12
resources/scripts/api/admin/locations/createLocation.ts
Normal file
12
resources/scripts/api/admin/locations/createLocation.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import http from '@/api/http';
|
||||
import { Location, rawDataToLocation } from '@/api/admin/locations/getLocations';
|
||||
|
||||
export default (short: string, long: string | null, include: string[] = []): Promise<Location> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post('/api/application/locations', {
|
||||
short, long,
|
||||
}, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToLocation(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
9
resources/scripts/api/admin/locations/deleteLocation.ts
Normal file
9
resources/scripts/api/admin/locations/deleteLocation.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import http from '@/api/http';
|
||||
|
||||
export default (id: number): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.delete(`/api/application/locations/${id}`)
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
10
resources/scripts/api/admin/locations/getLocation.ts
Normal file
10
resources/scripts/api/admin/locations/getLocation.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import http from '@/api/http';
|
||||
import { Location, rawDataToLocation } from '@/api/admin/locations/getLocations';
|
||||
|
||||
export default (id: number, include: string[] = []): Promise<Location> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/application/locations/${id}`, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToLocation(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
54
resources/scripts/api/admin/locations/getLocations.ts
Normal file
54
resources/scripts/api/admin/locations/getLocations.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
import http, { FractalResponseData, getPaginationSet, PaginatedResult } from '@/api/http';
|
||||
import { useContext } from 'react';
|
||||
import useSWR from 'swr';
|
||||
import { createContext } from '@/api/admin';
|
||||
|
||||
export interface Location {
|
||||
id: number;
|
||||
short: string;
|
||||
long: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export const rawDataToLocation = ({ attributes }: FractalResponseData): Location => ({
|
||||
id: attributes.id,
|
||||
short: attributes.short,
|
||||
long: attributes.long,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
});
|
||||
|
||||
export interface Filters {
|
||||
id?: string;
|
||||
short?: string;
|
||||
long?: string;
|
||||
}
|
||||
|
||||
export const Context = createContext<Filters>();
|
||||
|
||||
export default (include: string[] = []) => {
|
||||
const { page, filters, sort, sortDirection } = useContext(Context);
|
||||
|
||||
const params = {};
|
||||
if (filters !== null) {
|
||||
Object.keys(filters).forEach(key => {
|
||||
// @ts-ignore
|
||||
params['filter[' + key + ']'] = filters[key];
|
||||
});
|
||||
}
|
||||
|
||||
if (sort !== null) {
|
||||
// @ts-ignore
|
||||
params.sort = (sortDirection ? '-' : '') + sort;
|
||||
}
|
||||
|
||||
return useSWR<PaginatedResult<Location>>([ 'locations', page, filters, sort, sortDirection ], async () => {
|
||||
const { data } = await http.get('/api/application/locations', { params: { include: include.join(','), page, ...params } });
|
||||
|
||||
return ({
|
||||
items: (data.data || []).map(rawDataToLocation),
|
||||
pagination: getPaginationSet(data.meta.pagination),
|
||||
});
|
||||
});
|
||||
};
|
25
resources/scripts/api/admin/locations/searchLocations.ts
Normal file
25
resources/scripts/api/admin/locations/searchLocations.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import http from '@/api/http';
|
||||
import { Location, rawDataToLocation } from '@/api/admin/locations/getLocations';
|
||||
|
||||
interface Filters {
|
||||
short?: string;
|
||||
long?: string;
|
||||
}
|
||||
|
||||
export default (filters?: Filters): Promise<Location[]> => {
|
||||
const params = {};
|
||||
if (filters !== undefined) {
|
||||
Object.keys(filters).forEach(key => {
|
||||
// @ts-ignore
|
||||
params['filter[' + key + ']'] = filters[key];
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get('/api/application/locations', { params })
|
||||
.then(response => resolve(
|
||||
(response.data.data || []).map(rawDataToLocation)
|
||||
))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
12
resources/scripts/api/admin/locations/updateLocation.ts
Normal file
12
resources/scripts/api/admin/locations/updateLocation.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import http from '@/api/http';
|
||||
import { Location, rawDataToLocation } from '@/api/admin/locations/getLocations';
|
||||
|
||||
export default (id: number, short: string, long: string | null, include: string[] = []): Promise<Location> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.patch(`/api/application/locations/${id}`, {
|
||||
short, long,
|
||||
}, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToLocation(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
12
resources/scripts/api/admin/mounts/createMount.ts
Normal file
12
resources/scripts/api/admin/mounts/createMount.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import http from '@/api/http';
|
||||
import { Mount, rawDataToMount } from '@/api/admin/mounts/getMounts';
|
||||
|
||||
export default (name: string, description: string, source: string, target: string, readOnly: boolean, userMountable: boolean, include: string[] = []): Promise<Mount> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post('/api/application/mounts', {
|
||||
name, description, source, target, read_only: readOnly, user_mountable: userMountable,
|
||||
}, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToMount(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
9
resources/scripts/api/admin/mounts/deleteMount.ts
Normal file
9
resources/scripts/api/admin/mounts/deleteMount.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import http from '@/api/http';
|
||||
|
||||
export default (id: number): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.delete(`/api/application/mounts/${id}`)
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
10
resources/scripts/api/admin/mounts/getMount.ts
Normal file
10
resources/scripts/api/admin/mounts/getMount.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import http from '@/api/http';
|
||||
import { Mount, rawDataToMount } from '@/api/admin/mounts/getMounts';
|
||||
|
||||
export default (id: number, include: string[] = []): Promise<Mount> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/application/mounts/${id}`, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToMount(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
80
resources/scripts/api/admin/mounts/getMounts.ts
Normal file
80
resources/scripts/api/admin/mounts/getMounts.ts
Normal file
|
@ -0,0 +1,80 @@
|
|||
import http, { FractalResponseData, FractalResponseList, getPaginationSet, PaginatedResult } from '@/api/http';
|
||||
import { useContext } from 'react';
|
||||
import useSWR from 'swr';
|
||||
import { createContext } from '@/api/admin';
|
||||
import { Egg, rawDataToEgg } from '@/api/admin/eggs/getEgg';
|
||||
import { Node, rawDataToNode } from '@/api/admin/nodes/getNodes';
|
||||
import { Server, rawDataToServer } from '@/api/admin/servers/getServers';
|
||||
|
||||
export interface Mount {
|
||||
id: number;
|
||||
uuid: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
source: string;
|
||||
target: string;
|
||||
readOnly: boolean;
|
||||
userMountable: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
relations: {
|
||||
eggs: Egg[] | undefined;
|
||||
nodes: Node[] | undefined;
|
||||
servers: Server[] | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
export const rawDataToMount = ({ attributes }: FractalResponseData): Mount => ({
|
||||
id: attributes.id,
|
||||
uuid: attributes.uuid,
|
||||
name: attributes.name,
|
||||
description: attributes.description,
|
||||
source: attributes.source,
|
||||
target: attributes.target,
|
||||
readOnly: attributes.read_only,
|
||||
userMountable: attributes.user_mountable,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
|
||||
relations: {
|
||||
eggs: ((attributes.relationships?.eggs as FractalResponseList | undefined)?.data || []).map(rawDataToEgg),
|
||||
nodes: ((attributes.relationships?.nodes as FractalResponseList | undefined)?.data || []).map(rawDataToNode),
|
||||
servers: ((attributes.relationships?.servers as FractalResponseList | undefined)?.data || []).map(rawDataToServer),
|
||||
},
|
||||
});
|
||||
|
||||
export interface Filters {
|
||||
id?: string;
|
||||
name?: string;
|
||||
source?: string;
|
||||
target?: string;
|
||||
}
|
||||
|
||||
export const Context = createContext<Filters>();
|
||||
|
||||
export default (include: string[] = []) => {
|
||||
const { page, filters, sort, sortDirection } = useContext(Context);
|
||||
|
||||
const params = {};
|
||||
if (filters !== null) {
|
||||
Object.keys(filters).forEach(key => {
|
||||
// @ts-ignore
|
||||
params['filter[' + key + ']'] = filters[key];
|
||||
});
|
||||
}
|
||||
|
||||
if (sort !== null) {
|
||||
// @ts-ignore
|
||||
params.sort = (sortDirection ? '-' : '') + sort;
|
||||
}
|
||||
|
||||
return useSWR<PaginatedResult<Mount>>([ 'mounts', page, filters, sort, sortDirection ], async () => {
|
||||
const { data } = await http.get('/api/application/mounts', { params: { include: include.join(','), page, ...params } });
|
||||
|
||||
return ({
|
||||
items: (data.data || []).map(rawDataToMount),
|
||||
pagination: getPaginationSet(data.meta.pagination),
|
||||
});
|
||||
});
|
||||
};
|
12
resources/scripts/api/admin/mounts/updateMount.ts
Normal file
12
resources/scripts/api/admin/mounts/updateMount.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import http from '@/api/http';
|
||||
import { Mount, rawDataToMount } from '@/api/admin/mounts/getMounts';
|
||||
|
||||
export default (id: number, name: string, description: string | null, source: string, target: string, readOnly: boolean, userMountable: boolean, include: string[] = []): Promise<Mount> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.patch(`/api/application/mounts/${id}`, {
|
||||
name, description, source, target, read_only: readOnly, user_mountable: userMountable,
|
||||
}, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToMount(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
25
resources/scripts/api/admin/nest.ts
Normal file
25
resources/scripts/api/admin/nest.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { Model, UUID } from '@/api/admin/index';
|
||||
import { Egg } from '@/api/admin/egg';
|
||||
import http, { QueryBuilderParams, withQueryBuilderParams } from '@/api/http';
|
||||
import { Transformers } from '@definitions/admin';
|
||||
|
||||
export interface Nest extends Model {
|
||||
id: number;
|
||||
uuid: UUID;
|
||||
author: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
relationships: {
|
||||
eggs?: Egg[];
|
||||
};
|
||||
}
|
||||
|
||||
export const searchNests = async (params: QueryBuilderParams<'name'>): Promise<Nest[]> => {
|
||||
const { data } = await http.get('/api/application/nests', {
|
||||
params: withQueryBuilderParams(params),
|
||||
});
|
||||
|
||||
return data.data.map(Transformers.toNest);
|
||||
};
|
12
resources/scripts/api/admin/nests/createNest.ts
Normal file
12
resources/scripts/api/admin/nests/createNest.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import http from '@/api/http';
|
||||
import { Nest, rawDataToNest } from '@/api/admin/nests/getNests';
|
||||
|
||||
export default (name: string, description: string | null, include: string[] = []): Promise<Nest> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post('/api/application/nests', {
|
||||
name, description,
|
||||
}, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToNest(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
9
resources/scripts/api/admin/nests/deleteNest.ts
Normal file
9
resources/scripts/api/admin/nests/deleteNest.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import http from '@/api/http';
|
||||
|
||||
export default (id: number): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.delete(`/api/application/nests/${id}`)
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
38
resources/scripts/api/admin/nests/getEggs.ts
Normal file
38
resources/scripts/api/admin/nests/getEggs.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import http, { getPaginationSet, PaginatedResult } from '@/api/http';
|
||||
import { useContext } from 'react';
|
||||
import useSWR from 'swr';
|
||||
import { createContext } from '@/api/admin';
|
||||
import { Egg, rawDataToEgg } from '@/api/admin/eggs/getEgg';
|
||||
|
||||
export interface Filters {
|
||||
id?: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export const Context = createContext<Filters>();
|
||||
|
||||
export default (nestId: number, include: string[] = []) => {
|
||||
const { page, filters, sort, sortDirection } = useContext(Context);
|
||||
|
||||
const params = {};
|
||||
if (filters !== null) {
|
||||
Object.keys(filters).forEach(key => {
|
||||
// @ts-ignore
|
||||
params['filter[' + key + ']'] = filters[key];
|
||||
});
|
||||
}
|
||||
|
||||
if (sort !== null) {
|
||||
// @ts-ignore
|
||||
params.sort = (sortDirection ? '-' : '') + sort;
|
||||
}
|
||||
|
||||
return useSWR<PaginatedResult<Egg>>([ nestId, 'eggs', page, filters, sort, sortDirection ], async () => {
|
||||
const { data } = await http.get(`/api/application/nests/${nestId}/eggs`, { params: { include: include.join(','), page, ...params } });
|
||||
|
||||
return ({
|
||||
items: (data.data || []).map(rawDataToEgg),
|
||||
pagination: getPaginationSet(data.meta.pagination),
|
||||
});
|
||||
});
|
||||
};
|
10
resources/scripts/api/admin/nests/getNest.ts
Normal file
10
resources/scripts/api/admin/nests/getNest.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import http from '@/api/http';
|
||||
import { Nest, rawDataToNest } from '@/api/admin/nests/getNests';
|
||||
|
||||
export default (id: number, include: string[]): Promise<Nest> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/application/nests/${id}`, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToNest(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
66
resources/scripts/api/admin/nests/getNests.ts
Normal file
66
resources/scripts/api/admin/nests/getNests.ts
Normal file
|
@ -0,0 +1,66 @@
|
|||
import http, { FractalResponseData, FractalResponseList, getPaginationSet, PaginatedResult } from '@/api/http';
|
||||
import { useContext } from 'react';
|
||||
import useSWR from 'swr';
|
||||
import { createContext } from '@/api/admin';
|
||||
import { Egg, rawDataToEgg } from '@/api/admin/eggs/getEgg';
|
||||
|
||||
export interface Nest {
|
||||
id: number;
|
||||
uuid: string;
|
||||
author: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
relations: {
|
||||
eggs: Egg[] | undefined;
|
||||
},
|
||||
}
|
||||
|
||||
export const rawDataToNest = ({ attributes }: FractalResponseData): Nest => ({
|
||||
id: attributes.id,
|
||||
uuid: attributes.uuid,
|
||||
author: attributes.author,
|
||||
name: attributes.name,
|
||||
description: attributes.description,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
|
||||
relations: {
|
||||
eggs: ((attributes.relationships?.eggs as FractalResponseList | undefined)?.data || []).map(rawDataToEgg),
|
||||
},
|
||||
});
|
||||
|
||||
export interface Filters {
|
||||
id?: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export const Context = createContext<Filters>();
|
||||
|
||||
export default (include: string[] = []) => {
|
||||
const { page, filters, sort, sortDirection } = useContext(Context);
|
||||
|
||||
const params = {};
|
||||
if (filters !== null) {
|
||||
Object.keys(filters).forEach(key => {
|
||||
// @ts-ignore
|
||||
params['filter[' + key + ']'] = filters[key];
|
||||
});
|
||||
}
|
||||
|
||||
if (sort !== null) {
|
||||
// @ts-ignore
|
||||
params.sort = (sortDirection ? '-' : '') + sort;
|
||||
}
|
||||
|
||||
return useSWR<PaginatedResult<Nest>>([ 'nests', page, filters, sort, sortDirection ], async () => {
|
||||
const { data } = await http.get('/api/application/nests', { params: { include: include.join(','), page, ...params } });
|
||||
|
||||
return ({
|
||||
items: (data.data || []).map(rawDataToNest),
|
||||
pagination: getPaginationSet(data.meta.pagination),
|
||||
});
|
||||
});
|
||||
};
|
17
resources/scripts/api/admin/nests/importEgg.ts
Normal file
17
resources/scripts/api/admin/nests/importEgg.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import http from '@/api/http';
|
||||
import { Egg, rawDataToEgg } from '@/api/admin/eggs/getEgg';
|
||||
|
||||
export default (id: number, content: any, type = 'application/json', include: string[] = []): Promise<Egg> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post(`/api/application/nests/${id}/import`, content, {
|
||||
headers: {
|
||||
'Content-Type': type,
|
||||
},
|
||||
params: {
|
||||
include: include.join(','),
|
||||
},
|
||||
})
|
||||
.then(({ data }) => resolve(rawDataToEgg(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
12
resources/scripts/api/admin/nests/updateNest.ts
Normal file
12
resources/scripts/api/admin/nests/updateNest.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import http from '@/api/http';
|
||||
import { Nest, rawDataToNest } from '@/api/admin/nests/getNests';
|
||||
|
||||
export default (id: number, name: string, description: string | null, include: string[] = []): Promise<Nest> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.patch(`/api/application/nests/${id}`, {
|
||||
name, description,
|
||||
}, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToNest(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
84
resources/scripts/api/admin/node.ts
Normal file
84
resources/scripts/api/admin/node.ts
Normal file
|
@ -0,0 +1,84 @@
|
|||
import { Model, UUID, WithRelationships, withRelationships } from '@/api/admin/index';
|
||||
import { Location } from '@/api/admin/location';
|
||||
import http, { QueryBuilderParams, withQueryBuilderParams } from '@/api/http';
|
||||
import { Transformers } from '@definitions/admin';
|
||||
import { Server } from '@/api/admin/server';
|
||||
|
||||
interface NodePorts {
|
||||
http: {
|
||||
listen: number;
|
||||
public: number;
|
||||
};
|
||||
sftp: {
|
||||
listen: number;
|
||||
public: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Allocation extends Model {
|
||||
id: number;
|
||||
ip: string;
|
||||
port: number;
|
||||
alias: string | null;
|
||||
isAssigned: boolean;
|
||||
relationships: {
|
||||
node?: Node;
|
||||
server?: Server | null;
|
||||
};
|
||||
getDisplayText(): string;
|
||||
}
|
||||
|
||||
export interface Node extends Model {
|
||||
id: number;
|
||||
uuid: UUID;
|
||||
isPublic: boolean;
|
||||
locationId: number;
|
||||
databaseHostId: number;
|
||||
name: string;
|
||||
description: string | null;
|
||||
fqdn: string;
|
||||
ports: NodePorts;
|
||||
scheme: 'http' | 'https';
|
||||
isBehindProxy: boolean;
|
||||
isMaintenanceMode: boolean;
|
||||
memory: number;
|
||||
memoryOverallocate: number;
|
||||
disk: number;
|
||||
diskOverallocate: number;
|
||||
uploadSize: number;
|
||||
daemonBase: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
relationships: {
|
||||
location?: Location;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a single node and returns it.
|
||||
*/
|
||||
export const getNode = async (id: string | number): Promise<WithRelationships<Node, 'location'>> => {
|
||||
const { data } = await http.get(`/api/application/nodes/${id}`, {
|
||||
params: {
|
||||
include: [ 'location' ],
|
||||
},
|
||||
});
|
||||
|
||||
return withRelationships(Transformers.toNode(data.data), 'location');
|
||||
};
|
||||
|
||||
export const searchNodes = async (params: QueryBuilderParams<'name'>): Promise<Node[]> => {
|
||||
const { data } = await http.get('/api/application/nodes', {
|
||||
params: withQueryBuilderParams(params),
|
||||
});
|
||||
|
||||
return data.data.map(Transformers.toNode);
|
||||
};
|
||||
|
||||
export const getAllocations = async (id: string | number, params?: QueryBuilderParams<'ip' | 'server_id'>): Promise<Allocation[]> => {
|
||||
const { data } = await http.get(`/api/application/nodes/${id}/allocations`, {
|
||||
params: withQueryBuilderParams(params),
|
||||
});
|
||||
|
||||
return data.data.map(Transformers.toAllocation);
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
import http from '@/api/http';
|
||||
import { Allocation, rawDataToAllocation } from '@/api/admin/nodes/getAllocations';
|
||||
|
||||
export interface Values {
|
||||
ip: string;
|
||||
ports: number[];
|
||||
alias?: string;
|
||||
}
|
||||
|
||||
export default (id: string | number, values: Values, include: string[] = []): Promise<Allocation[]> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post(`/api/application/nodes/${id}/allocations`, values, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve((data || []).map(rawDataToAllocation)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
import http from '@/api/http';
|
||||
|
||||
export default (nodeId: number, allocationId: number): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.delete(`/api/application/nodes/${nodeId}/allocations/${allocationId}`)
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
import { Allocation, rawDataToAllocation } from '@/api/admin/nodes/getAllocations';
|
||||
import http, { getPaginationSet, PaginatedResult } from '@/api/http';
|
||||
import { useContext } from 'react';
|
||||
import useSWR from 'swr';
|
||||
import { createContext } from '@/api/admin';
|
||||
|
||||
export interface Filters {
|
||||
id?: string;
|
||||
ip?: string;
|
||||
port?: string;
|
||||
}
|
||||
|
||||
export const Context = createContext<Filters>();
|
||||
|
||||
export default (id: number, include: string[] = []) => {
|
||||
const { page, filters, sort, sortDirection } = useContext(Context);
|
||||
|
||||
const params = {};
|
||||
if (filters !== null) {
|
||||
Object.keys(filters).forEach(key => {
|
||||
// @ts-ignore
|
||||
params['filter[' + key + ']'] = filters[key];
|
||||
});
|
||||
}
|
||||
|
||||
if (sort !== null) {
|
||||
// @ts-ignore
|
||||
params.sort = (sortDirection ? '-' : '') + sort;
|
||||
}
|
||||
|
||||
return useSWR<PaginatedResult<Allocation>>([ 'allocations', page, filters, sort, sortDirection ], async () => {
|
||||
const { data } = await http.get(`/api/application/nodes/${id}/allocations`, { params: { include: include.join(','), page, ...params } });
|
||||
|
||||
return ({
|
||||
items: (data.data || []).map(rawDataToAllocation),
|
||||
pagination: getPaginationSet(data.meta.pagination),
|
||||
});
|
||||
});
|
||||
};
|
42
resources/scripts/api/admin/nodes/createNode.ts
Normal file
42
resources/scripts/api/admin/nodes/createNode.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
import http from '@/api/http';
|
||||
import { Node, rawDataToNode } from '@/api/admin/nodes/getNodes';
|
||||
|
||||
export interface Values {
|
||||
name: string;
|
||||
locationId: number;
|
||||
databaseHostId: number | null;
|
||||
fqdn: string;
|
||||
scheme: string;
|
||||
behindProxy: boolean;
|
||||
public: boolean;
|
||||
daemonBase: string;
|
||||
|
||||
memory: number;
|
||||
memoryOverallocate: number;
|
||||
disk: number;
|
||||
diskOverallocate: number;
|
||||
|
||||
listenPortHTTP: number;
|
||||
publicPortHTTP: number;
|
||||
listenPortSFTP: number;
|
||||
publicPortSFTP: number;
|
||||
}
|
||||
|
||||
export default (values: Values, include: string[] = []): Promise<Node> => {
|
||||
const data = {};
|
||||
|
||||
Object.keys(values).forEach((key) => {
|
||||
const key2 = key
|
||||
.replace('HTTP', 'Http')
|
||||
.replace('SFTP', 'Sftp')
|
||||
.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
|
||||
// @ts-ignore
|
||||
data[key2] = values[key];
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post('/api/application/nodes', data, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToNode(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
9
resources/scripts/api/admin/nodes/deleteNode.ts
Normal file
9
resources/scripts/api/admin/nodes/deleteNode.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import http from '@/api/http';
|
||||
|
||||
export default (id: number): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.delete(`/api/application/nodes/${id}`)
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
61
resources/scripts/api/admin/nodes/getAllocations.ts
Normal file
61
resources/scripts/api/admin/nodes/getAllocations.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
import http, { FractalResponseData } from '@/api/http';
|
||||
import { rawDataToServer, Server } from '@/api/admin/servers/getServers';
|
||||
|
||||
export interface Allocation {
|
||||
id: number;
|
||||
ip: string;
|
||||
port: number;
|
||||
alias: string | null;
|
||||
serverId: number | null;
|
||||
assigned: boolean;
|
||||
|
||||
relations: {
|
||||
server?: Server;
|
||||
}
|
||||
|
||||
getDisplayText (): string;
|
||||
}
|
||||
|
||||
export const rawDataToAllocation = ({ attributes }: FractalResponseData): Allocation => ({
|
||||
id: attributes.id,
|
||||
ip: attributes.ip,
|
||||
port: attributes.port,
|
||||
alias: attributes.alias || null,
|
||||
serverId: attributes.server_id,
|
||||
assigned: attributes.assigned,
|
||||
|
||||
relations: {
|
||||
server: attributes.relationships?.server?.object === 'server' ? rawDataToServer(attributes.relationships.server as FractalResponseData) : undefined,
|
||||
},
|
||||
|
||||
// TODO: If IP is an IPv6, wrap IP in [].
|
||||
getDisplayText (): string {
|
||||
if (attributes.alias !== null) {
|
||||
return `${attributes.ip}:${attributes.port} (${attributes.alias})`;
|
||||
}
|
||||
return `${attributes.ip}:${attributes.port}`;
|
||||
},
|
||||
});
|
||||
|
||||
export interface Filters {
|
||||
ip?: string
|
||||
/* eslint-disable camelcase */
|
||||
server_id?: string;
|
||||
/* eslint-enable camelcase */
|
||||
}
|
||||
|
||||
export default (id: string | number, filters: Filters = {}, include: string[] = []): Promise<Allocation[]> => {
|
||||
const params = {};
|
||||
if (filters !== null) {
|
||||
Object.keys(filters).forEach(key => {
|
||||
// @ts-ignore
|
||||
params['filter[' + key + ']'] = filters[key];
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/application/nodes/${id}/allocations`, { params: { include: include.join(','), ...params } })
|
||||
.then(({ data }) => resolve((data.data || []).map(rawDataToAllocation)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
10
resources/scripts/api/admin/nodes/getNode.ts
Normal file
10
resources/scripts/api/admin/nodes/getNode.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import http from '@/api/http';
|
||||
import { Node, rawDataToNode } from '@/api/admin/nodes/getNodes';
|
||||
|
||||
export default (id: number, include: string[] = []): Promise<Node> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/application/nodes/${id}`, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToNode(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
import http from '@/api/http';
|
||||
|
||||
export default (id: number): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/application/nodes/${id}/configuration?format=yaml`)
|
||||
.then(({ data }) => resolve(data))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
19
resources/scripts/api/admin/nodes/getNodeInformation.ts
Normal file
19
resources/scripts/api/admin/nodes/getNodeInformation.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import http from '@/api/http';
|
||||
|
||||
export interface NodeInformation {
|
||||
version: string;
|
||||
system: {
|
||||
type: string;
|
||||
arch: string;
|
||||
release: string;
|
||||
cpus: number;
|
||||
};
|
||||
}
|
||||
|
||||
export default (id: number): Promise<NodeInformation> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/application/nodes/${id}/information`)
|
||||
.then(({ data }) => resolve(data))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
107
resources/scripts/api/admin/nodes/getNodes.ts
Normal file
107
resources/scripts/api/admin/nodes/getNodes.ts
Normal file
|
@ -0,0 +1,107 @@
|
|||
import http, { FractalResponseData, getPaginationSet, PaginatedResult } from '@/api/http';
|
||||
import { useContext } from 'react';
|
||||
import useSWR from 'swr';
|
||||
import { createContext } from '@/api/admin';
|
||||
import { Database, rawDataToDatabase } from '@/api/admin/databases/getDatabases';
|
||||
import { Location, rawDataToLocation } from '@/api/admin/locations/getLocations';
|
||||
|
||||
export interface Node {
|
||||
id: number;
|
||||
uuid: string;
|
||||
public: boolean;
|
||||
name: string;
|
||||
description: string | null;
|
||||
locationId: number;
|
||||
databaseHostId: number | null;
|
||||
fqdn: string;
|
||||
listenPortHTTP: number;
|
||||
publicPortHTTP: number;
|
||||
listenPortSFTP: number;
|
||||
publicPortSFTP: number;
|
||||
scheme: string;
|
||||
behindProxy: boolean;
|
||||
maintenanceMode: boolean;
|
||||
memory: number;
|
||||
memoryOverallocate: number;
|
||||
disk: number;
|
||||
diskOverallocate: number;
|
||||
uploadSize: number;
|
||||
daemonBase: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
relations: {
|
||||
databaseHost: Database | undefined;
|
||||
location: Location | undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export const rawDataToNode = ({ attributes }: FractalResponseData): Node => ({
|
||||
id: attributes.id,
|
||||
uuid: attributes.uuid,
|
||||
public: attributes.public,
|
||||
name: attributes.name,
|
||||
description: attributes.description,
|
||||
locationId: attributes.location_id,
|
||||
databaseHostId: attributes.database_host_id,
|
||||
fqdn: attributes.fqdn,
|
||||
listenPortHTTP: attributes.listen_port_http,
|
||||
publicPortHTTP: attributes.public_port_http,
|
||||
listenPortSFTP: attributes.listen_port_sftp,
|
||||
publicPortSFTP: attributes.public_port_sftp,
|
||||
scheme: attributes.scheme,
|
||||
behindProxy: attributes.behind_proxy,
|
||||
maintenanceMode: attributes.maintenance_mode,
|
||||
memory: attributes.memory,
|
||||
memoryOverallocate: attributes.memory_overallocate,
|
||||
disk: attributes.disk,
|
||||
diskOverallocate: attributes.disk_overallocate,
|
||||
uploadSize: attributes.upload_size,
|
||||
daemonBase: attributes.daemon_base,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
|
||||
relations: {
|
||||
// eslint-disable-next-line camelcase
|
||||
databaseHost: attributes.relationships?.database_host !== undefined && attributes.relationships?.database_host.object !== 'null_resource' ? rawDataToDatabase(attributes.relationships.database_host as FractalResponseData) : undefined,
|
||||
location: attributes.relationships?.location !== undefined ? rawDataToLocation(attributes.relationships.location as FractalResponseData) : undefined,
|
||||
},
|
||||
});
|
||||
|
||||
export interface Filters {
|
||||
id?: string;
|
||||
uuid?: string;
|
||||
name?: string;
|
||||
image?: string;
|
||||
/* eslint-disable camelcase */
|
||||
external_id?: string;
|
||||
/* eslint-enable camelcase */
|
||||
}
|
||||
|
||||
export const Context = createContext<Filters>();
|
||||
|
||||
export default (include: string[] = []) => {
|
||||
const { page, filters, sort, sortDirection } = useContext(Context);
|
||||
|
||||
const params = {};
|
||||
if (filters !== null) {
|
||||
Object.keys(filters).forEach(key => {
|
||||
// @ts-ignore
|
||||
params['filter[' + key + ']'] = filters[key];
|
||||
});
|
||||
}
|
||||
|
||||
if (sort !== null) {
|
||||
// @ts-ignore
|
||||
params.sort = (sortDirection ? '-' : '') + sort;
|
||||
}
|
||||
|
||||
return useSWR<PaginatedResult<Node>>([ 'nodes', page, filters, sort, sortDirection ], async () => {
|
||||
const { data } = await http.get('/api/application/nodes', { params: { include: include.join(','), page, ...params } });
|
||||
|
||||
return ({
|
||||
items: (data.data || []).map(rawDataToNode),
|
||||
pagination: getPaginationSet(data.meta.pagination),
|
||||
});
|
||||
});
|
||||
};
|
21
resources/scripts/api/admin/nodes/updateNode.ts
Normal file
21
resources/scripts/api/admin/nodes/updateNode.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import http from '@/api/http';
|
||||
import { Node, rawDataToNode } from '@/api/admin/nodes/getNodes';
|
||||
|
||||
export default (id: number, node: Partial<Node>, include: string[] = []): Promise<Node> => {
|
||||
const data = {};
|
||||
|
||||
Object.keys(node).forEach((key) => {
|
||||
const key2 = key
|
||||
.replace('HTTP', 'Http')
|
||||
.replace('SFTP', 'Sftp')
|
||||
.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
|
||||
// @ts-ignore
|
||||
data[key2] = node[key];
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
http.patch(`/api/application/nodes/${id}`, data, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToNode(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
103
resources/scripts/api/admin/roles.ts
Normal file
103
resources/scripts/api/admin/roles.ts
Normal file
|
@ -0,0 +1,103 @@
|
|||
import http, { getPaginationSet, PaginatedResult } from '@/api/http';
|
||||
import { Transformers, UserRole } from '@definitions/admin';
|
||||
import { useContext } from 'react';
|
||||
import useSWR from 'swr';
|
||||
import { createContext } from '@/api/admin/index';
|
||||
|
||||
export interface Filters {
|
||||
id?: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export const Context = createContext<Filters>();
|
||||
|
||||
const createRole = (name: string, description: string | null, include: string[] = []): Promise<UserRole> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post('/api/application/roles', {
|
||||
name, description,
|
||||
}, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(Transformers.toUserRole(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
const deleteRole = (id: number): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.delete(`/api/application/roles/${id}`)
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
const getRole = (id: number, include: string[] = []): Promise<UserRole> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/application/roles/${id}`, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(Transformers.toUserRole(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
const searchRoles = (filters?: { name?: string }): Promise<UserRole[]> => {
|
||||
const params = {};
|
||||
if (filters !== undefined) {
|
||||
Object.keys(filters).forEach(key => {
|
||||
// @ts-ignore
|
||||
params['filter[' + key + ']'] = filters[key];
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get('/api/application/roles', { params })
|
||||
.then(response => resolve(
|
||||
(response.data.data || []).map(Transformers.toUserRole)
|
||||
))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
const updateRole = (id: number, name: string, description: string | null, include: string[] = []): Promise<UserRole> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.patch(`/api/application/roles/${id}`, {
|
||||
name, description,
|
||||
}, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(Transformers.toUserRole(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
const getRoles = (include: string[] = []) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const { page, filters, sort, sortDirection } = useContext(Context);
|
||||
|
||||
const params = {};
|
||||
if (filters !== null) {
|
||||
Object.keys(filters).forEach(key => {
|
||||
// @ts-ignore
|
||||
params['filter[' + key + ']'] = filters[key];
|
||||
});
|
||||
}
|
||||
|
||||
if (sort !== null) {
|
||||
// @ts-ignore
|
||||
params.sort = (sortDirection ? '-' : '') + sort;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
return useSWR<PaginatedResult<UserRole>>([ 'roles', page, filters, sort, sortDirection ], async () => {
|
||||
const { data } = await http.get('/api/application/roles', { params: { include: include.join(','), page, ...params } });
|
||||
|
||||
return ({
|
||||
items: (data.data || []).map(Transformers.toUserRole),
|
||||
pagination: getPaginationSet(data.meta.pagination),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
createRole,
|
||||
deleteRole,
|
||||
getRole,
|
||||
searchRoles,
|
||||
updateRole,
|
||||
getRoles,
|
||||
};
|
99
resources/scripts/api/admin/server.ts
Normal file
99
resources/scripts/api/admin/server.ts
Normal file
|
@ -0,0 +1,99 @@
|
|||
import useSWR, { SWRResponse } from 'swr';
|
||||
import { AxiosError } from 'axios';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import http from '@/api/http';
|
||||
import { Model, UUID, withRelationships, WithRelationships } from '@/api/admin/index';
|
||||
import { Allocation, Node } from '@/api/admin/node';
|
||||
import { Transformers, User } from '@definitions/admin';
|
||||
import { Egg, EggVariable } from '@/api/admin/egg';
|
||||
import { Nest } from '@/api/admin/nest';
|
||||
|
||||
/**
|
||||
* Defines the limits for a server that exists on the Panel.
|
||||
*/
|
||||
interface ServerLimits {
|
||||
memory: number;
|
||||
swap: number;
|
||||
disk: number;
|
||||
io: number;
|
||||
cpu: number;
|
||||
threads: string | null;
|
||||
oomDisabled: boolean;
|
||||
}
|
||||
|
||||
export interface ServerVariable extends EggVariable {
|
||||
serverValue: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a single server instance that is returned from the Panel's admin
|
||||
* API endpoints.
|
||||
*/
|
||||
export interface Server extends Model {
|
||||
id: number;
|
||||
uuid: UUID;
|
||||
externalId: string | null;
|
||||
identifier: string;
|
||||
name: string;
|
||||
description: string;
|
||||
status: string;
|
||||
userId: number;
|
||||
nodeId: number;
|
||||
allocationId: number;
|
||||
eggId: number;
|
||||
nestId: number;
|
||||
limits: ServerLimits;
|
||||
featureLimits: {
|
||||
databases: number;
|
||||
allocations: number;
|
||||
backups: number;
|
||||
};
|
||||
container: {
|
||||
startup: string | null;
|
||||
image: string;
|
||||
environment: Record<string, string>;
|
||||
};
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
relationships: {
|
||||
allocations?: Allocation[];
|
||||
nest?: Nest;
|
||||
egg?: Egg;
|
||||
node?: Node;
|
||||
user?: User;
|
||||
variables?: ServerVariable[];
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A standard API response with the minimum viable details for the frontend
|
||||
* to correctly render a server.
|
||||
*/
|
||||
type LoadedServer = WithRelationships<Server, 'allocations' | 'user' | 'node'>;
|
||||
|
||||
/**
|
||||
* Fetches a server from the API and ensures that the allocations, user, and
|
||||
* node data is loaded.
|
||||
*/
|
||||
export const getServer = async (id: number | string): Promise<LoadedServer> => {
|
||||
const { data } = await http.get(`/api/application/servers/${id}`, {
|
||||
params: {
|
||||
include: ['allocations', 'user', 'node', 'variables'],
|
||||
},
|
||||
});
|
||||
|
||||
return withRelationships(Transformers.toServer(data), 'allocations', 'user', 'node', 'variables');
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an SWR instance by automatically loading in the server for the currently
|
||||
* loaded route match in the admin area.
|
||||
*/
|
||||
export const useServerFromRoute = (): SWRResponse<LoadedServer, AxiosError> => {
|
||||
const params = useParams<'id'>();
|
||||
|
||||
return useSWR(`/api/application/servers/${params.id}`, async () => getServer(Number(params.id)), {
|
||||
revalidateOnMount: false,
|
||||
revalidateOnFocus: false,
|
||||
});
|
||||
};
|
80
resources/scripts/api/admin/servers/createServer.ts
Normal file
80
resources/scripts/api/admin/servers/createServer.ts
Normal file
|
@ -0,0 +1,80 @@
|
|||
import http from '@/api/http';
|
||||
import { Server, rawDataToServer } from '@/api/admin/servers/getServers';
|
||||
|
||||
export interface CreateServerRequest {
|
||||
externalId: string;
|
||||
name: string;
|
||||
description: string | null;
|
||||
ownerId: number;
|
||||
nodeId: number;
|
||||
|
||||
limits: {
|
||||
memory: number;
|
||||
swap: number;
|
||||
disk: number;
|
||||
io: number;
|
||||
cpu: number;
|
||||
threads: string;
|
||||
oomDisabled: boolean;
|
||||
}
|
||||
|
||||
featureLimits: {
|
||||
allocations: number;
|
||||
backups: number;
|
||||
databases: number;
|
||||
};
|
||||
|
||||
allocation: {
|
||||
default: number;
|
||||
additional: number[];
|
||||
};
|
||||
|
||||
startup: string;
|
||||
environment: Record<string, any>;
|
||||
eggId: number;
|
||||
image: string;
|
||||
skipScripts: boolean;
|
||||
startOnCompletion: boolean;
|
||||
}
|
||||
|
||||
export default (r: CreateServerRequest, include: string[] = []): Promise<Server> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post('/api/application/servers', {
|
||||
externalId: r.externalId,
|
||||
name: r.name,
|
||||
description: r.description,
|
||||
owner_id: r.ownerId,
|
||||
node_id: r.nodeId,
|
||||
|
||||
limits: {
|
||||
cpu: r.limits.cpu,
|
||||
disk: r.limits.disk,
|
||||
io: r.limits.io,
|
||||
memory: r.limits.memory,
|
||||
swap: r.limits.swap,
|
||||
threads: r.limits.threads,
|
||||
oom_killer: r.limits.oomDisabled,
|
||||
},
|
||||
|
||||
feature_limits: {
|
||||
allocations: r.featureLimits.allocations,
|
||||
backups: r.featureLimits.backups,
|
||||
databases: r.featureLimits.databases,
|
||||
},
|
||||
|
||||
allocation: {
|
||||
default: r.allocation.default,
|
||||
additional: r.allocation.additional,
|
||||
},
|
||||
|
||||
startup: r.startup,
|
||||
environment: r.environment,
|
||||
egg_id: r.eggId,
|
||||
image: r.image,
|
||||
skip_scripts: r.skipScripts,
|
||||
start_on_completion: r.startOnCompletion,
|
||||
}, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToServer(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
9
resources/scripts/api/admin/servers/deleteServer.ts
Normal file
9
resources/scripts/api/admin/servers/deleteServer.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import http from '@/api/http';
|
||||
|
||||
export default (id: number): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.delete(`/api/application/servers/${id}`)
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
10
resources/scripts/api/admin/servers/getServer.ts
Normal file
10
resources/scripts/api/admin/servers/getServer.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import http from '@/api/http';
|
||||
import { Server, rawDataToServer } from '@/api/admin/servers/getServers';
|
||||
|
||||
export default (id: number, include: string[]): Promise<Server> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/application/servers/${id}`, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToServer(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
177
resources/scripts/api/admin/servers/getServers.ts
Normal file
177
resources/scripts/api/admin/servers/getServers.ts
Normal file
|
@ -0,0 +1,177 @@
|
|||
import { Allocation, rawDataToAllocation } from '@/api/admin/nodes/getAllocations';
|
||||
import { useContext } from 'react';
|
||||
import useSWR from 'swr';
|
||||
import { createContext } from '@/api/admin';
|
||||
import http, { FractalResponseData, FractalResponseList, getPaginationSet, PaginatedResult } from '@/api/http';
|
||||
import { Egg, rawDataToEgg } from '@/api/admin/eggs/getEgg';
|
||||
import { Node, rawDataToNode } from '@/api/admin/nodes/getNodes';
|
||||
import { Transformers, User } from '@definitions/admin';
|
||||
|
||||
export interface ServerVariable {
|
||||
id: number;
|
||||
eggId: number;
|
||||
name: string;
|
||||
description: string;
|
||||
envVariable: string;
|
||||
defaultValue: string;
|
||||
userViewable: boolean;
|
||||
userEditable: boolean;
|
||||
rules: string;
|
||||
required: boolean;
|
||||
serverValue: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export const rawDataToServerVariable = ({ attributes }: FractalResponseData): ServerVariable => ({
|
||||
id: attributes.id,
|
||||
eggId: attributes.egg_id,
|
||||
name: attributes.name,
|
||||
description: attributes.description,
|
||||
envVariable: attributes.env_variable,
|
||||
defaultValue: attributes.default_value,
|
||||
userViewable: attributes.user_viewable,
|
||||
userEditable: attributes.user_editable,
|
||||
rules: attributes.rules,
|
||||
required: attributes.required,
|
||||
serverValue: attributes.server_value,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
});
|
||||
|
||||
export interface Server {
|
||||
id: number;
|
||||
externalId: string | null
|
||||
uuid: string;
|
||||
identifier: string;
|
||||
name: string;
|
||||
description: string;
|
||||
status: string;
|
||||
|
||||
limits: {
|
||||
memory: number;
|
||||
swap: number;
|
||||
disk: number;
|
||||
io: number;
|
||||
cpu: number;
|
||||
threads: string | null;
|
||||
oomDisabled: boolean;
|
||||
}
|
||||
|
||||
featureLimits: {
|
||||
databases: number;
|
||||
allocations: number;
|
||||
backups: number;
|
||||
}
|
||||
|
||||
ownerId: number;
|
||||
nodeId: number;
|
||||
allocationId: number;
|
||||
nestId: number;
|
||||
eggId: number;
|
||||
|
||||
container: {
|
||||
startup: string;
|
||||
image: string;
|
||||
environment: Map<string, string>;
|
||||
}
|
||||
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
relations: {
|
||||
allocations?: Allocation[];
|
||||
egg?: Egg;
|
||||
node?: Node;
|
||||
user?: User;
|
||||
variables: ServerVariable[];
|
||||
}
|
||||
}
|
||||
|
||||
export const rawDataToServer = ({ attributes }: FractalResponseData): Server => ({
|
||||
id: attributes.id,
|
||||
externalId: attributes.external_id,
|
||||
uuid: attributes.uuid,
|
||||
identifier: attributes.identifier,
|
||||
name: attributes.name,
|
||||
description: attributes.description,
|
||||
status: attributes.status,
|
||||
|
||||
limits: {
|
||||
memory: attributes.limits.memory,
|
||||
swap: attributes.limits.swap,
|
||||
disk: attributes.limits.disk,
|
||||
io: attributes.limits.io,
|
||||
cpu: attributes.limits.cpu,
|
||||
threads: attributes.limits.threads,
|
||||
oomDisabled: attributes.limits.oom_disabled,
|
||||
},
|
||||
|
||||
featureLimits: {
|
||||
databases: attributes.feature_limits.databases,
|
||||
allocations: attributes.feature_limits.allocations,
|
||||
backups: attributes.feature_limits.backups,
|
||||
},
|
||||
|
||||
ownerId: attributes.owner_id,
|
||||
nodeId: attributes.node_id,
|
||||
allocationId: attributes.allocation_id,
|
||||
nestId: attributes.nest_id,
|
||||
eggId: attributes.egg_id,
|
||||
|
||||
container: {
|
||||
startup: attributes.container.startup,
|
||||
image: attributes.container.image,
|
||||
environment: attributes.container.environment,
|
||||
},
|
||||
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
|
||||
relations: {
|
||||
allocations: ((attributes.relationships?.allocations as FractalResponseList | undefined)?.data || []).map(rawDataToAllocation),
|
||||
egg: attributes.relationships?.egg?.object === 'egg' ? rawDataToEgg(attributes.relationships.egg as FractalResponseData) : undefined,
|
||||
node: attributes.relationships?.node?.object === 'node' ? rawDataToNode(attributes.relationships.node as FractalResponseData) : undefined,
|
||||
user: attributes.relationships?.user?.object === 'user' ? Transformers.toUser(attributes.relationships.user as FractalResponseData) : undefined,
|
||||
variables: ((attributes.relationships?.variables as FractalResponseList | undefined)?.data || []).map(rawDataToServerVariable),
|
||||
},
|
||||
}) as Server;
|
||||
|
||||
export interface Filters {
|
||||
id?: string;
|
||||
uuid?: string;
|
||||
name?: string;
|
||||
/* eslint-disable camelcase */
|
||||
owner_id?: string;
|
||||
node_id?: string;
|
||||
external_id?: string;
|
||||
/* eslint-enable camelcase */
|
||||
}
|
||||
|
||||
export const Context = createContext<Filters>();
|
||||
|
||||
export default (include: string[] = []) => {
|
||||
const { page, filters, sort, sortDirection } = useContext(Context);
|
||||
|
||||
const params = {};
|
||||
if (filters !== null) {
|
||||
Object.keys(filters).forEach(key => {
|
||||
// @ts-ignore
|
||||
params['filter[' + key + ']'] = filters[key];
|
||||
});
|
||||
}
|
||||
|
||||
if (sort !== null) {
|
||||
// @ts-ignore
|
||||
params.sort = (sortDirection ? '-' : '') + sort;
|
||||
}
|
||||
|
||||
return useSWR<PaginatedResult<Server>>([ 'servers', page, filters, sort, sortDirection ], async () => {
|
||||
const { data } = await http.get('/api/application/servers', { params: { include: include.join(','), page, ...params } });
|
||||
|
||||
return ({
|
||||
items: (data.data || []).map(rawDataToServer),
|
||||
pagination: getPaginationSet(data.meta.pagination),
|
||||
});
|
||||
});
|
||||
};
|
64
resources/scripts/api/admin/servers/updateServer.ts
Normal file
64
resources/scripts/api/admin/servers/updateServer.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
import http from '@/api/http';
|
||||
import { Server, rawDataToServer } from '@/api/admin/servers/getServers';
|
||||
|
||||
export interface Values {
|
||||
externalId: string;
|
||||
name: string;
|
||||
ownerId: number;
|
||||
|
||||
limits: {
|
||||
memory: number;
|
||||
swap: number;
|
||||
disk: number;
|
||||
io: number;
|
||||
cpu: number;
|
||||
threads: string;
|
||||
oomDisabled: boolean;
|
||||
}
|
||||
|
||||
featureLimits: {
|
||||
allocations: number;
|
||||
backups: number;
|
||||
databases: number;
|
||||
}
|
||||
|
||||
allocationId: number;
|
||||
addAllocations: number[];
|
||||
removeAllocations: number[];
|
||||
}
|
||||
|
||||
export default (id: number, server: Partial<Values>, include: string[] = []): Promise<Server> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.patch(
|
||||
`/api/application/servers/${id}`,
|
||||
{
|
||||
external_id: server.externalId,
|
||||
name: server.name,
|
||||
owner_id: server.ownerId,
|
||||
|
||||
limits: {
|
||||
memory: server.limits?.memory,
|
||||
swap: server.limits?.swap,
|
||||
disk: server.limits?.disk,
|
||||
io: server.limits?.io,
|
||||
cpu: server.limits?.cpu,
|
||||
threads: server.limits?.threads,
|
||||
oom_killer: server.limits?.oomDisabled,
|
||||
},
|
||||
|
||||
feature_limits: {
|
||||
allocations: server.featureLimits?.allocations,
|
||||
backups: server.featureLimits?.backups,
|
||||
databases: server.featureLimits?.databases,
|
||||
},
|
||||
|
||||
allocation_id: server.allocationId,
|
||||
add_allocations: server.addAllocations,
|
||||
remove_allocations: server.removeAllocations,
|
||||
},
|
||||
{ params: { include: include.join(',') } }
|
||||
)
|
||||
.then(({ data }) => resolve(rawDataToServer(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
28
resources/scripts/api/admin/servers/updateServerStartup.ts
Normal file
28
resources/scripts/api/admin/servers/updateServerStartup.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import http from '@/api/http';
|
||||
import { Server, rawDataToServer } from '@/api/admin/servers/getServers';
|
||||
|
||||
export interface Values {
|
||||
startup: string;
|
||||
environment: Record<string, any>;
|
||||
eggId: number;
|
||||
image: string;
|
||||
skipScripts: boolean;
|
||||
}
|
||||
|
||||
export default (id: number, values: Partial<Values>, include: string[] = []): Promise<Server> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.patch(
|
||||
`/api/application/servers/${id}/startup`,
|
||||
{
|
||||
startup: values.startup !== '' ? values.startup : null,
|
||||
environment: values.environment,
|
||||
egg_id: values.eggId,
|
||||
image: values.image,
|
||||
skip_scripts: values.skipScripts,
|
||||
},
|
||||
{ params: { include: include.join(',') } }
|
||||
)
|
||||
.then(({ data }) => resolve(rawDataToServer(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
96
resources/scripts/api/admin/users.ts
Normal file
96
resources/scripts/api/admin/users.ts
Normal file
|
@ -0,0 +1,96 @@
|
|||
import http, {
|
||||
FractalPaginatedResponse,
|
||||
PaginatedResult,
|
||||
QueryBuilderParams,
|
||||
getPaginationSet,
|
||||
withQueryBuilderParams,
|
||||
} from '@/api/http';
|
||||
import { Transformers, User } from '@definitions/admin';
|
||||
import useSWR, { SWRConfiguration, SWRResponse } from 'swr';
|
||||
import { AxiosError } from 'axios';
|
||||
|
||||
export interface UpdateUserValues {
|
||||
externalId: string;
|
||||
username: string;
|
||||
email: string;
|
||||
password: string;
|
||||
adminRoleId: number | null;
|
||||
rootAdmin: boolean;
|
||||
}
|
||||
|
||||
const filters = ['id', 'uuid', 'external_id', 'username', 'email'] as const;
|
||||
type Filters = typeof filters[number];
|
||||
|
||||
const useGetUsers = (
|
||||
params?: QueryBuilderParams<Filters>,
|
||||
config?: SWRConfiguration,
|
||||
): SWRResponse<PaginatedResult<User>, AxiosError> => {
|
||||
return useSWR<PaginatedResult<User>>(
|
||||
['/api/application/users', JSON.stringify(params)],
|
||||
async () => {
|
||||
const { data } = await http.get<FractalPaginatedResponse>('/api/application/users', {
|
||||
params: withQueryBuilderParams(params),
|
||||
});
|
||||
|
||||
return getPaginationSet(data, Transformers.toUser);
|
||||
},
|
||||
config || { revalidateOnMount: true, revalidateOnFocus: false },
|
||||
);
|
||||
};
|
||||
|
||||
const getUser = (id: number, include: string[] = []): Promise<User> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/application/users/${id}`, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(Transformers.toUser(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
const searchUserAccounts = async (params: QueryBuilderParams<'username' | 'email'>): Promise<User[]> => {
|
||||
const { data } = await http.get('/api/application/users', {
|
||||
params: withQueryBuilderParams(params),
|
||||
});
|
||||
|
||||
return data.data.map(Transformers.toUser);
|
||||
};
|
||||
|
||||
const createUser = (values: UpdateUserValues, include: string[] = []): Promise<User> => {
|
||||
const data = {};
|
||||
Object.keys(values).forEach(k => {
|
||||
// @ts-ignore
|
||||
data[k.replace(/[A-Z]/g, l => `_${l.toLowerCase()}`)] = values[k];
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post('/api/application/users', data, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(Transformers.toUser(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
const updateUser = (id: number, values: Partial<UpdateUserValues>, include: string[] = []): Promise<User> => {
|
||||
const data = {};
|
||||
Object.keys(values).forEach(k => {
|
||||
// Don't set password if it is empty.
|
||||
if (k === 'password' && values[k] === '') {
|
||||
return;
|
||||
}
|
||||
// @ts-ignore
|
||||
data[k.replace(/[A-Z]/g, l => `_${l.toLowerCase()}`)] = values[k];
|
||||
});
|
||||
return new Promise((resolve, reject) => {
|
||||
http.patch(`/api/application/users/${id}`, data, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(Transformers.toUser(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
const deleteUser = (id: number): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.delete(`/api/application/users/${id}`)
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
export { useGetUsers, getUser, searchUserAccounts, createUser, updateUser, deleteUser };
|
2
resources/scripts/api/definitions/admin/index.ts
Normal file
2
resources/scripts/api/definitions/admin/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from './models.d';
|
||||
export { default as Transformers } from './transformers';
|
29
resources/scripts/api/definitions/admin/models.d.ts
vendored
Normal file
29
resources/scripts/api/definitions/admin/models.d.ts
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
import { ModelWithRelationships, UUID } from '@/api/definitions';
|
||||
import { Server } from '@/api/admin/server';
|
||||
|
||||
interface User extends ModelWithRelationships {
|
||||
id: number;
|
||||
uuid: UUID;
|
||||
externalId: string;
|
||||
username: string;
|
||||
email: string;
|
||||
language: string;
|
||||
adminRoleId: number | null;
|
||||
roleName: string;
|
||||
isRootAdmin: boolean;
|
||||
isUsingTwoFactor: boolean;
|
||||
avatarUrl: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
relationships: {
|
||||
role: UserRole | null;
|
||||
// TODO: just use an API call, this is probably a bad idea for performance.
|
||||
servers?: Server[];
|
||||
};
|
||||
}
|
||||
|
||||
interface UserRole extends ModelWithRelationships {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
}
|
212
resources/scripts/api/definitions/admin/transformers.ts
Normal file
212
resources/scripts/api/definitions/admin/transformers.ts
Normal file
|
@ -0,0 +1,212 @@
|
|||
/* eslint-disable camelcase */
|
||||
import { Allocation, Node } from '@/api/admin/node';
|
||||
import { Server, ServerVariable } from '@/api/admin/server';
|
||||
import { FractalResponseData, FractalResponseList } from '@/api/http';
|
||||
import * as Models from '@definitions/admin/models';
|
||||
import { Location } from '@/api/admin/location';
|
||||
import { Egg, EggVariable } from '@/api/admin/egg';
|
||||
import { Nest } from '@/api/admin/nest';
|
||||
|
||||
const isList = (data: FractalResponseList | FractalResponseData): data is FractalResponseList => data.object === 'list';
|
||||
|
||||
function transform<T, M = undefined> (data: undefined, transformer: (callback: FractalResponseData) => T, missing?: M): undefined;
|
||||
function transform<T, M> (data: FractalResponseData | undefined, transformer: (callback: FractalResponseData) => T, missing?: M): T | M | undefined;
|
||||
function transform<T, M> (data: FractalResponseList | undefined, transformer: (callback: FractalResponseData) => T, missing?: M): T[] | undefined;
|
||||
function transform<T> (data: FractalResponseData | FractalResponseList | undefined, transformer: (callback: FractalResponseData) => T, missing = undefined) {
|
||||
if (data === undefined) return undefined;
|
||||
|
||||
if (isList(data)) {
|
||||
return data.data.map(transformer);
|
||||
}
|
||||
|
||||
return !data ? missing : transformer(data);
|
||||
}
|
||||
|
||||
export default class Transformers {
|
||||
static toServer = ({ attributes }: FractalResponseData): Server => {
|
||||
const { oom_disabled, ...limits } = attributes.limits;
|
||||
const { allocations, egg, nest, node, user, variables } = attributes.relationships || {};
|
||||
|
||||
return {
|
||||
id: attributes.id,
|
||||
uuid: attributes.uuid,
|
||||
externalId: attributes.external_id,
|
||||
identifier: attributes.identifier,
|
||||
name: attributes.name,
|
||||
description: attributes.description,
|
||||
status: attributes.status,
|
||||
userId: attributes.owner_id,
|
||||
nodeId: attributes.node_id,
|
||||
allocationId: attributes.allocation_id,
|
||||
eggId: attributes.egg_id,
|
||||
nestId: attributes.nest_id,
|
||||
limits: { ...limits, oomDisabled: oom_disabled },
|
||||
featureLimits: attributes.feature_limits,
|
||||
container: attributes.container,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
relationships: {
|
||||
allocations: transform(allocations as FractalResponseList | undefined, this.toAllocation),
|
||||
nest: transform(nest as FractalResponseData | undefined, this.toNest),
|
||||
egg: transform(egg as FractalResponseData | undefined, this.toEgg),
|
||||
node: transform(node as FractalResponseData | undefined, this.toNode),
|
||||
user: transform(user as FractalResponseData | undefined, this.toUser),
|
||||
variables: transform(variables as FractalResponseList | undefined, this.toServerEggVariable),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
static toNode = ({ attributes }: FractalResponseData): Node => {
|
||||
return {
|
||||
id: attributes.id,
|
||||
uuid: attributes.uuid,
|
||||
isPublic: attributes.public,
|
||||
locationId: attributes.location_id,
|
||||
databaseHostId: attributes.database_host_id,
|
||||
name: attributes.name,
|
||||
description: attributes.description,
|
||||
fqdn: attributes.fqdn,
|
||||
ports: {
|
||||
http: {
|
||||
public: attributes.publicPortHttp,
|
||||
listen: attributes.listenPortHttp,
|
||||
},
|
||||
sftp: {
|
||||
public: attributes.publicPortSftp,
|
||||
listen: attributes.listenPortSftp,
|
||||
},
|
||||
},
|
||||
scheme: attributes.scheme,
|
||||
isBehindProxy: attributes.behindProxy,
|
||||
isMaintenanceMode: attributes.maintenance_mode,
|
||||
memory: attributes.memory,
|
||||
memoryOverallocate: attributes.memory_overallocate,
|
||||
disk: attributes.disk,
|
||||
diskOverallocate: attributes.disk_overallocate,
|
||||
uploadSize: attributes.upload_size,
|
||||
daemonBase: attributes.daemonBase,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
relationships: {
|
||||
location: transform(attributes.relationships?.location as FractalResponseData, this.toLocation),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
static toUserRole = ({ attributes }: FractalResponseData): Models.UserRole => ({
|
||||
id: attributes.id,
|
||||
name: attributes.name,
|
||||
description: attributes.description,
|
||||
relationships: {},
|
||||
});
|
||||
|
||||
static toUser = ({ attributes }: FractalResponseData): Models.User => {
|
||||
return {
|
||||
id: attributes.id,
|
||||
uuid: attributes.uuid,
|
||||
externalId: attributes.external_id,
|
||||
username: attributes.username,
|
||||
email: attributes.email,
|
||||
language: attributes.language,
|
||||
adminRoleId: attributes.adminRoleId || null,
|
||||
roleName: attributes.role_name,
|
||||
isRootAdmin: attributes.root_admin,
|
||||
isUsingTwoFactor: attributes['2fa'] || false,
|
||||
avatarUrl: attributes.avatar_url,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
relationships: {
|
||||
role: transform(attributes.relationships?.role as FractalResponseData, this.toUserRole) || null,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
static toLocation = ({ attributes }: FractalResponseData): Location => ({
|
||||
id: attributes.id,
|
||||
short: attributes.short,
|
||||
long: attributes.long,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
relationships: {
|
||||
nodes: transform(attributes.relationships?.node as FractalResponseList, this.toNode),
|
||||
},
|
||||
});
|
||||
|
||||
static toEgg = ({ attributes }: FractalResponseData): Egg => ({
|
||||
id: attributes.id,
|
||||
uuid: attributes.uuid,
|
||||
nestId: attributes.nest_id,
|
||||
author: attributes.author,
|
||||
name: attributes.name,
|
||||
description: attributes.description,
|
||||
features: attributes.features,
|
||||
dockerImages: attributes.docker_images,
|
||||
configFiles: attributes.config?.files,
|
||||
configStartup: attributes.config?.startup,
|
||||
configStop: attributes.config?.stop,
|
||||
configFrom: attributes.config?.extends,
|
||||
startup: attributes.startup,
|
||||
copyScriptFrom: attributes.copy_script_from,
|
||||
scriptContainer: attributes.script?.container,
|
||||
scriptEntry: attributes.script?.entry,
|
||||
scriptIsPrivileged: attributes.script?.privileged,
|
||||
scriptInstall: attributes.script?.install,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
relationships: {
|
||||
nest: transform(attributes.relationships?.nest as FractalResponseData, this.toNest),
|
||||
variables: transform(attributes.relationships?.variables as FractalResponseList, this.toEggVariable),
|
||||
},
|
||||
});
|
||||
|
||||
static toEggVariable = ({ attributes }: FractalResponseData): EggVariable => ({
|
||||
id: attributes.id,
|
||||
eggId: attributes.egg_id,
|
||||
name: attributes.name,
|
||||
description: attributes.description,
|
||||
environmentVariable: attributes.env_variable,
|
||||
defaultValue: attributes.default_value,
|
||||
isUserViewable: attributes.user_viewable,
|
||||
isUserEditable: attributes.user_editable,
|
||||
// isRequired: attributes.required,
|
||||
rules: attributes.rules,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
relationships: {},
|
||||
});
|
||||
|
||||
static toServerEggVariable = (data: FractalResponseData): ServerVariable => ({
|
||||
...this.toEggVariable(data),
|
||||
serverValue: data.attributes.server_value,
|
||||
});
|
||||
|
||||
static toAllocation = ({ attributes }: FractalResponseData): Allocation => ({
|
||||
id: attributes.id,
|
||||
ip: attributes.ip,
|
||||
port: attributes.port,
|
||||
alias: attributes.alias || null,
|
||||
isAssigned: attributes.assigned,
|
||||
relationships: {
|
||||
node: transform(attributes.relationships?.node as FractalResponseData, this.toNode),
|
||||
server: transform(attributes.relationships?.server as FractalResponseData, this.toServer),
|
||||
},
|
||||
getDisplayText (): string {
|
||||
const raw = `${this.ip}:${this.port}`;
|
||||
|
||||
return !this.alias ? raw : `${this.alias} (${raw})`;
|
||||
},
|
||||
});
|
||||
|
||||
static toNest = ({ attributes }: FractalResponseData): Nest => ({
|
||||
id: attributes.id,
|
||||
uuid: attributes.uuid,
|
||||
author: attributes.author,
|
||||
name: attributes.name,
|
||||
description: attributes.description,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
relationships: {
|
||||
eggs: transform(attributes.relationships?.eggs as FractalResponseList, this.toEgg),
|
||||
},
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue