Apply new eslint rules; default to prettier for styling
This commit is contained in:
parent
f22cce8881
commit
dc84af9937
218 changed files with 3876 additions and 3564 deletions
|
@ -8,19 +8,26 @@ import useFilteredObject from '@/plugins/useFilteredObject';
|
|||
|
||||
export type ActivityLogFilters = QueryBuilderParams<'ip' | 'event', 'timestamp'>;
|
||||
|
||||
const useActivityLogs = (filters?: ActivityLogFilters, config?: ConfigInterface<PaginatedResult<ActivityLog>, AxiosError>): responseInterface<PaginatedResult<ActivityLog>, AxiosError> => {
|
||||
const key = useUserSWRContentKey([ 'account', 'activity', JSON.stringify(useFilteredObject(filters || {})) ]);
|
||||
const useActivityLogs = (
|
||||
filters?: ActivityLogFilters,
|
||||
config?: ConfigInterface<PaginatedResult<ActivityLog>, AxiosError>
|
||||
): responseInterface<PaginatedResult<ActivityLog>, AxiosError> => {
|
||||
const key = useUserSWRContentKey(['account', 'activity', JSON.stringify(useFilteredObject(filters || {}))]);
|
||||
|
||||
return useSWR<PaginatedResult<ActivityLog>>(key, async () => {
|
||||
const { data } = await http.get('/api/client/account/activity', {
|
||||
params: {
|
||||
...withQueryBuilderParams(filters),
|
||||
include: [ 'actor' ],
|
||||
},
|
||||
});
|
||||
return useSWR<PaginatedResult<ActivityLog>>(
|
||||
key,
|
||||
async () => {
|
||||
const { data } = await http.get('/api/client/account/activity', {
|
||||
params: {
|
||||
...withQueryBuilderParams(filters),
|
||||
include: ['actor'],
|
||||
},
|
||||
});
|
||||
|
||||
return toPaginatedSet(data, Transformers.toActivityLog);
|
||||
}, { revalidateOnMount: false, ...(config || {}) });
|
||||
return toPaginatedSet(data, Transformers.toActivityLog);
|
||||
},
|
||||
{ revalidateOnMount: false, ...(config || {}) }
|
||||
);
|
||||
};
|
||||
|
||||
export { useActivityLogs };
|
||||
|
|
|
@ -7,11 +7,13 @@ export default (description: string, allowedIps: string): Promise<ApiKey & { sec
|
|||
description,
|
||||
allowed_ips: allowedIps.length > 0 ? allowedIps.split('\n') : [],
|
||||
})
|
||||
.then(({ data }) => resolve({
|
||||
...rawDataToApiKey(data.attributes),
|
||||
// eslint-disable-next-line camelcase
|
||||
secretToken: data.meta?.secret_token ?? '',
|
||||
}))
|
||||
.then(({ data }) =>
|
||||
resolve({
|
||||
...rawDataToApiKey(data.attributes),
|
||||
// eslint-disable-next-line camelcase
|
||||
secretToken: data.meta?.secret_token ?? '',
|
||||
})
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -5,15 +5,19 @@ import { SSHKey, Transformers } from '@definitions/user';
|
|||
import { AxiosError } from 'axios';
|
||||
|
||||
const useSSHKeys = (config?: ConfigInterface<SSHKey[], AxiosError>) => {
|
||||
const key = useUserSWRContentKey([ 'account', 'ssh-keys' ]);
|
||||
const key = useUserSWRContentKey(['account', 'ssh-keys']);
|
||||
|
||||
return useSWR(key, async () => {
|
||||
const { data } = await http.get('/api/client/account/ssh-keys');
|
||||
return useSWR(
|
||||
key,
|
||||
async () => {
|
||||
const { data } = await http.get('/api/client/account/ssh-keys');
|
||||
|
||||
return (data as FractalResponseList).data.map((datum: any) => {
|
||||
return Transformers.toSSHKey(datum.attributes);
|
||||
});
|
||||
}, { revalidateOnMount: false, ...(config || {}) });
|
||||
return (data as FractalResponseList).data.map((datum: any) => {
|
||||
return Transformers.toSSHKey(datum.attributes);
|
||||
});
|
||||
},
|
||||
{ revalidateOnMount: false, ...(config || {}) }
|
||||
);
|
||||
};
|
||||
|
||||
const createSSHKey = async (name: string, publicKey: string): Promise<SSHKey> => {
|
||||
|
|
|
@ -15,12 +15,14 @@ export interface LoginData {
|
|||
export default ({ username, password, recaptchaData }: LoginData): Promise<LoginResponse> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get('/sanctum/csrf-cookie')
|
||||
.then(() => http.post('/auth/login', {
|
||||
user: username,
|
||||
password,
|
||||
'g-recaptcha-response': recaptchaData,
|
||||
}))
|
||||
.then(response => {
|
||||
.then(() =>
|
||||
http.post('/auth/login', {
|
||||
user: username,
|
||||
password,
|
||||
'g-recaptcha-response': recaptchaData,
|
||||
})
|
||||
)
|
||||
.then((response) => {
|
||||
if (!(response.data instanceof Object)) {
|
||||
return reject(new Error('An error occurred while processing the login request.'));
|
||||
}
|
||||
|
|
|
@ -6,12 +6,14 @@ export default (token: string, code: string, recoveryToken?: string): Promise<Lo
|
|||
http.post('/auth/login/checkpoint', {
|
||||
confirmation_token: token,
|
||||
authentication_code: code,
|
||||
recovery_token: (recoveryToken && recoveryToken.length > 0) ? recoveryToken : undefined,
|
||||
recovery_token: recoveryToken && recoveryToken.length > 0 ? recoveryToken : undefined,
|
||||
})
|
||||
.then(response => resolve({
|
||||
complete: response.data.data.complete,
|
||||
intended: response.data.data.intended || undefined,
|
||||
}))
|
||||
.then((response) =>
|
||||
resolve({
|
||||
complete: response.data.data.complete,
|
||||
intended: response.data.data.intended || undefined,
|
||||
})
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -19,10 +19,12 @@ export default (email: string, data: Data): Promise<PasswordResetResponse> => {
|
|||
password: data.password,
|
||||
password_confirmation: data.passwordConfirmation,
|
||||
})
|
||||
.then(response => resolve({
|
||||
redirectTo: response.data.redirect_to,
|
||||
sendToLogin: response.data.send_to_login,
|
||||
}))
|
||||
.then((response) =>
|
||||
resolve({
|
||||
redirectTo: response.data.redirect_to,
|
||||
sendToLogin: response.data.send_to_login,
|
||||
})
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ import http from '@/api/http';
|
|||
export default (email: string, recaptchaData?: string): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post('/auth/password', { email, 'g-recaptcha-response': recaptchaData })
|
||||
.then(response => resolve(response.data.status || ''))
|
||||
.then((response) => resolve(response.data.status || ''))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -12,9 +12,21 @@ type TransformerFunc<T> = (callback: FractalResponseData) => T;
|
|||
const isList = (data: FractalResponseList | FractalResponseData): data is FractalResponseList => data.object === 'list';
|
||||
|
||||
function transform<T, M>(data: null | undefined, transformer: TransformerFunc<T>, missing?: M): M;
|
||||
function transform<T, M>(data: FractalResponseData | null | undefined, transformer: TransformerFunc<T>, missing?: M): T | M;
|
||||
function transform<T, M>(data: FractalResponseList | FractalPaginatedResponse | null | undefined, transformer: TransformerFunc<T>, missing?: M): T[] | M;
|
||||
function transform<T> (data: FractalResponseData | FractalResponseList | FractalPaginatedResponse | null | undefined, transformer: TransformerFunc<T>, missing = undefined) {
|
||||
function transform<T, M>(
|
||||
data: FractalResponseData | null | undefined,
|
||||
transformer: TransformerFunc<T>,
|
||||
missing?: M
|
||||
): T | M;
|
||||
function transform<T, M>(
|
||||
data: FractalResponseList | FractalPaginatedResponse | null | undefined,
|
||||
transformer: TransformerFunc<T>,
|
||||
missing?: M
|
||||
): T[] | M;
|
||||
function transform<T>(
|
||||
data: FractalResponseData | FractalResponseList | FractalPaginatedResponse | null | undefined,
|
||||
transformer: TransformerFunc<T>,
|
||||
missing = undefined
|
||||
) {
|
||||
if (data === undefined || data === null) {
|
||||
return missing;
|
||||
}
|
||||
|
@ -30,9 +42,9 @@ function transform<T> (data: FractalResponseData | FractalResponseList | Fractal
|
|||
return transformer(data);
|
||||
}
|
||||
|
||||
function toPaginatedSet<T extends TransformerFunc<Model>> (
|
||||
function toPaginatedSet<T extends TransformerFunc<Model>>(
|
||||
response: FractalPaginatedResponse,
|
||||
transformer: T,
|
||||
transformer: T
|
||||
): PaginatedResult<ReturnType<T>> {
|
||||
return {
|
||||
items: transform(response, transformer) as ReturnType<T>[],
|
||||
|
|
2
resources/scripts/api/definitions/index.d.ts
vendored
2
resources/scripts/api/definitions/index.d.ts
vendored
|
@ -22,7 +22,7 @@ interface ModelWithRelationships extends Model {
|
|||
*/
|
||||
type WithLoaded<M extends ModelWithRelationships, R extends keyof M['relationships']> = M & {
|
||||
relationships: MarkRequired<M['relationships'], R>;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper type that allows you to infer the type of an object by giving
|
||||
|
|
|
@ -9,7 +9,7 @@ interface User extends Model {
|
|||
twoFactorEnabled: boolean;
|
||||
createdAt: Date;
|
||||
permissions: SubuserPermission[];
|
||||
can (permission: SubuserPermission): boolean;
|
||||
can(permission: SubuserPermission): boolean;
|
||||
}
|
||||
|
||||
interface SSHKey extends Model {
|
||||
|
@ -30,5 +30,5 @@ interface ActivityLog extends Model<'actor'> {
|
|||
timestamp: Date;
|
||||
relationships: {
|
||||
actor: User | null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ export default class Transformers {
|
|||
fingerprint: data.fingerprint,
|
||||
createdAt: new Date(data.created_at),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
static toUser = ({ attributes }: FractalResponseData): Models.User => {
|
||||
return {
|
||||
|
@ -21,11 +21,11 @@ export default class Transformers {
|
|||
twoFactorEnabled: attributes['2fa_enabled'],
|
||||
permissions: attributes.permissions || [],
|
||||
createdAt: new Date(attributes.created_at),
|
||||
can (permission): boolean {
|
||||
can(permission): boolean {
|
||||
return this.permissions.includes(permission);
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
static toActivityLog = ({ attributes }: FractalResponseData): Models.ActivityLog => {
|
||||
const { actor } = attributes.relationships || {};
|
||||
|
@ -43,8 +43,7 @@ export default class Transformers {
|
|||
actor: transform(actor as FractalResponseData, this.toUser, null),
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export class MetaTransformers {
|
||||
}
|
||||
export class MetaTransformers {}
|
||||
|
|
|
@ -15,10 +15,12 @@ export default ({ query, ...params }: QueryParams): Promise<PaginatedResult<Serv
|
|||
...params,
|
||||
},
|
||||
})
|
||||
.then(({ data }) => resolve({
|
||||
items: (data.data || []).map((datum: any) => rawDataToServerObject(datum)),
|
||||
pagination: getPaginationSet(data.meta.pagination),
|
||||
}))
|
||||
.then(({ data }) =>
|
||||
resolve({
|
||||
items: (data.data || []).map((datum: any) => rawDataToServerObject(datum)),
|
||||
pagination: getPaginationSet(data.meta.pagination),
|
||||
})
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ const http: AxiosInstance = axios.create({
|
|||
},
|
||||
});
|
||||
|
||||
http.interceptors.request.use(req => {
|
||||
http.interceptors.request.use((req) => {
|
||||
if (!req.url?.endsWith('/resources')) {
|
||||
store.getActions().progress.startContinuous();
|
||||
}
|
||||
|
@ -19,17 +19,20 @@ http.interceptors.request.use(req => {
|
|||
return req;
|
||||
});
|
||||
|
||||
http.interceptors.response.use(resp => {
|
||||
if (!resp.request?.url?.endsWith('/resources')) {
|
||||
http.interceptors.response.use(
|
||||
(resp) => {
|
||||
if (!resp.request?.url?.endsWith('/resources')) {
|
||||
store.getActions().progress.setComplete();
|
||||
}
|
||||
|
||||
return resp;
|
||||
},
|
||||
(error) => {
|
||||
store.getActions().progress.setComplete();
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
return resp;
|
||||
}, error => {
|
||||
store.getActions().progress.setComplete();
|
||||
|
||||
throw error;
|
||||
});
|
||||
);
|
||||
|
||||
export default http;
|
||||
|
||||
|
@ -37,7 +40,7 @@ export default http;
|
|||
* Converts an error into a human readable response. Mostly just a generic helper to
|
||||
* make sure we display the message from the server back to the user if we can.
|
||||
*/
|
||||
export function httpErrorToHuman (error: any): string {
|
||||
export function httpErrorToHuman(error: any): string {
|
||||
if (error.response && error.response.data) {
|
||||
let { data } = error.response;
|
||||
|
||||
|
@ -104,7 +107,7 @@ export interface PaginationDataSet {
|
|||
totalPages: number;
|
||||
}
|
||||
|
||||
export function getPaginationSet (data: any): PaginationDataSet {
|
||||
export function getPaginationSet(data: any): PaginationDataSet {
|
||||
return {
|
||||
total: data.total,
|
||||
count: data.count,
|
||||
|
@ -142,11 +145,11 @@ export const withQueryBuilderParams = (data?: QueryBuilderParams): Record<string
|
|||
|
||||
const sorts = Object.keys(data.sorts || {}).reduce((arr, key) => {
|
||||
const value = data.sorts?.[key];
|
||||
if (!value || ![ 'asc', 'desc', 1, -1 ].includes(value)) {
|
||||
if (!value || !['asc', 'desc', 1, -1].includes(value)) {
|
||||
return arr;
|
||||
}
|
||||
|
||||
return [ ...arr, (value === -1 || value === 'desc' ? '-' : '') + key ];
|
||||
return [...arr, (value === -1 || value === 'desc' ? '-' : '') + key];
|
||||
}, [] as string[]);
|
||||
|
||||
return {
|
||||
|
|
|
@ -3,14 +3,17 @@ import { AxiosError } from 'axios';
|
|||
import { History } from 'history';
|
||||
|
||||
export const setupInterceptors = (history: History) => {
|
||||
http.interceptors.response.use(resp => resp, (error: AxiosError) => {
|
||||
if (error.response?.status === 400) {
|
||||
if (error.response?.data.errors?.[0].code === 'TwoFactorAuthRequiredException') {
|
||||
if (!window.location.pathname.startsWith('/account')) {
|
||||
history.replace('/account', { twoFactorRedirect: true });
|
||||
http.interceptors.response.use(
|
||||
(resp) => resp,
|
||||
(error: AxiosError) => {
|
||||
if (error.response?.status === 400) {
|
||||
if (error.response?.data.errors?.[0].code === 'TwoFactorAuthRequiredException') {
|
||||
if (!window.location.pathname.startsWith('/account')) {
|
||||
history.replace('/account', { twoFactorRedirect: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
);
|
||||
};
|
||||
|
|
|
@ -9,20 +9,27 @@ import { ServerContext } from '@/state/server';
|
|||
|
||||
export type ActivityLogFilters = QueryBuilderParams<'ip' | 'event', 'timestamp'>;
|
||||
|
||||
const useActivityLogs = (filters?: ActivityLogFilters, config?: ConfigInterface<PaginatedResult<ActivityLog>, AxiosError>): responseInterface<PaginatedResult<ActivityLog>, AxiosError> => {
|
||||
const uuid = ServerContext.useStoreState(state => state.server.data?.uuid);
|
||||
const key = useUserSWRContentKey([ 'server', 'activity', useFilteredObject(filters || {}) ]);
|
||||
const useActivityLogs = (
|
||||
filters?: ActivityLogFilters,
|
||||
config?: ConfigInterface<PaginatedResult<ActivityLog>, AxiosError>
|
||||
): responseInterface<PaginatedResult<ActivityLog>, AxiosError> => {
|
||||
const uuid = ServerContext.useStoreState((state) => state.server.data?.uuid);
|
||||
const key = useUserSWRContentKey(['server', 'activity', useFilteredObject(filters || {})]);
|
||||
|
||||
return useSWR<PaginatedResult<ActivityLog>>(key, async () => {
|
||||
const { data } = await http.get(`/api/client/servers/${uuid}/activity`, {
|
||||
params: {
|
||||
...withQueryBuilderParams(filters),
|
||||
include: [ 'actor' ],
|
||||
},
|
||||
});
|
||||
return useSWR<PaginatedResult<ActivityLog>>(
|
||||
key,
|
||||
async () => {
|
||||
const { data } = await http.get(`/api/client/servers/${uuid}/activity`, {
|
||||
params: {
|
||||
...withQueryBuilderParams(filters),
|
||||
include: ['actor'],
|
||||
},
|
||||
});
|
||||
|
||||
return toPaginatedSet(data, Transformers.toActivityLog);
|
||||
}, { revalidateOnMount: false, ...(config || {}) });
|
||||
return toPaginatedSet(data, Transformers.toActivityLog);
|
||||
},
|
||||
{ revalidateOnMount: false, ...(config || {}) }
|
||||
);
|
||||
};
|
||||
|
||||
export { useActivityLogs };
|
||||
|
|
|
@ -3,13 +3,17 @@ import http from '@/api/http';
|
|||
|
||||
export default (uuid: string, data: { connectionsFrom: string; databaseName: string }): Promise<ServerDatabase> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post(`/api/client/servers/${uuid}/databases`, {
|
||||
database: data.databaseName,
|
||||
remote: data.connectionsFrom,
|
||||
}, {
|
||||
params: { include: 'password' },
|
||||
})
|
||||
.then(response => resolve(rawDataToServerDatabase(response.data.attributes)))
|
||||
http.post(
|
||||
`/api/client/servers/${uuid}/databases`,
|
||||
{
|
||||
database: data.databaseName,
|
||||
remote: data.connectionsFrom,
|
||||
},
|
||||
{
|
||||
params: { include: 'password' },
|
||||
}
|
||||
)
|
||||
.then((response) => resolve(rawDataToServerDatabase(response.data.attributes)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -15,7 +15,8 @@ export const rawDataToServerDatabase = (data: any): ServerDatabase => ({
|
|||
username: data.username,
|
||||
connectionString: `${data.host.address}:${data.host.port}`,
|
||||
allowConnectionsFrom: data.connections_from,
|
||||
password: data.relationships && data.relationships.password ? data.relationships.password.attributes.password : undefined,
|
||||
password:
|
||||
data.relationships && data.relationships.password ? data.relationships.password.attributes.password : undefined,
|
||||
});
|
||||
|
||||
export default (uuid: string, includePassword = true): Promise<ServerDatabase[]> => {
|
||||
|
@ -23,9 +24,9 @@ export default (uuid: string, includePassword = true): Promise<ServerDatabase[]>
|
|||
http.get(`/api/client/servers/${uuid}/databases`, {
|
||||
params: includePassword ? { include: 'password' } : undefined,
|
||||
})
|
||||
.then(response => resolve(
|
||||
(response.data.data || []).map((item: any) => rawDataToServerDatabase(item.attributes))
|
||||
))
|
||||
.then((response) =>
|
||||
resolve((response.data.data || []).map((item: any) => rawDataToServerDatabase(item.attributes)))
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -3,10 +3,15 @@ import http from '@/api/http';
|
|||
import { rawDataToFileObject } from '@/api/transformers';
|
||||
|
||||
export default async (uuid: string, directory: string, files: string[]): Promise<FileObject> => {
|
||||
const { data } = await http.post(`/api/client/servers/${uuid}/files/compress`, { root: directory, files }, {
|
||||
timeout: 60000,
|
||||
timeoutErrorMessage: 'It looks like this archive is taking a long time to generate. It will appear once completed.',
|
||||
});
|
||||
const { data } = await http.post(
|
||||
`/api/client/servers/${uuid}/files/compress`,
|
||||
{ root: directory, files },
|
||||
{
|
||||
timeout: 60000,
|
||||
timeoutErrorMessage:
|
||||
'It looks like this archive is taking a long time to generate. It will appear once completed.',
|
||||
}
|
||||
);
|
||||
|
||||
return rawDataToFileObject(data);
|
||||
};
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import http from '@/api/http';
|
||||
|
||||
export default async (uuid: string, directory: string, file: string): Promise<void> => {
|
||||
await http.post(`/api/client/servers/${uuid}/files/decompress`, { root: directory, file }, {
|
||||
timeout: 300000,
|
||||
timeoutErrorMessage: 'It looks like this archive is taking a long time to be unarchived. Once completed the unarchived files will appear.',
|
||||
});
|
||||
await http.post(
|
||||
`/api/client/servers/${uuid}/files/decompress`,
|
||||
{ root: directory, file },
|
||||
{
|
||||
timeout: 300000,
|
||||
timeoutErrorMessage:
|
||||
'It looks like this archive is taking a long time to be unarchived. Once completed the unarchived files will appear.',
|
||||
}
|
||||
);
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@ export default (server: string, file: string): Promise<string> => {
|
|||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/client/servers/${server}/files/contents`, {
|
||||
params: { file },
|
||||
transformResponse: res => res,
|
||||
transformResponse: (res) => res,
|
||||
responseType: 'text',
|
||||
})
|
||||
.then(({ data }) => resolve(data))
|
||||
|
|
|
@ -5,7 +5,7 @@ export interface FileObject {
|
|||
key: string;
|
||||
name: string;
|
||||
mode: string;
|
||||
modeBits: string,
|
||||
modeBits: string;
|
||||
size: number;
|
||||
isFile: boolean;
|
||||
isSymlink: boolean;
|
||||
|
|
|
@ -58,24 +58,30 @@ export const rawDataToServerObject = ({ attributes: data }: FractalResponseData)
|
|||
ip: data.sftp_details.ip,
|
||||
port: data.sftp_details.port,
|
||||
},
|
||||
description: data.description ? ((data.description.length > 0) ? data.description : null) : null,
|
||||
description: data.description ? (data.description.length > 0 ? data.description : null) : null,
|
||||
limits: { ...data.limits },
|
||||
eggFeatures: data.egg_features || [],
|
||||
featureLimits: { ...data.feature_limits },
|
||||
isInstalling: data.status === 'installing' || data.status === 'install_failed',
|
||||
isTransferring: data.is_transferring,
|
||||
variables: ((data.relationships?.variables as FractalResponseList | undefined)?.data || []).map(rawDataToServerEggVariable),
|
||||
allocations: ((data.relationships?.allocations as FractalResponseList | undefined)?.data || []).map(rawDataToServerAllocation),
|
||||
variables: ((data.relationships?.variables as FractalResponseList | undefined)?.data || []).map(
|
||||
rawDataToServerEggVariable
|
||||
),
|
||||
allocations: ((data.relationships?.allocations as FractalResponseList | undefined)?.data || []).map(
|
||||
rawDataToServerAllocation
|
||||
),
|
||||
});
|
||||
|
||||
export default (uuid: string): Promise<[ Server, string[] ]> => {
|
||||
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 || []),
|
||||
]))
|
||||
.then(({ data }) =>
|
||||
resolve([
|
||||
rawDataToServerObject(data),
|
||||
// eslint-disable-next-line camelcase
|
||||
data.meta?.is_server_owner ? ['*'] : data.meta?.user_permissions || [],
|
||||
])
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -16,16 +16,18 @@ export interface ServerStats {
|
|||
export default (server: string): Promise<ServerStats> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/client/servers/${server}/resources`)
|
||||
.then(({ data: { attributes } }) => resolve({
|
||||
status: attributes.current_state,
|
||||
isSuspended: attributes.is_suspended,
|
||||
memoryUsageInBytes: attributes.resources.memory_bytes,
|
||||
cpuUsagePercent: attributes.resources.cpu_absolute,
|
||||
diskUsageInBytes: attributes.resources.disk_bytes,
|
||||
networkRxInBytes: attributes.resources.network_rx_bytes,
|
||||
networkTxInBytes: attributes.resources.network_tx_bytes,
|
||||
uptime: attributes.resources.uptime,
|
||||
}))
|
||||
.then(({ data: { attributes } }) =>
|
||||
resolve({
|
||||
status: attributes.current_state,
|
||||
isSuspended: attributes.is_suspended,
|
||||
memoryUsageInBytes: attributes.resources.memory_bytes,
|
||||
cpuUsagePercent: attributes.resources.cpu_absolute,
|
||||
diskUsageInBytes: attributes.resources.disk_bytes,
|
||||
networkRxInBytes: attributes.resources.network_rx_bytes,
|
||||
networkTxInBytes: attributes.resources.network_tx_bytes,
|
||||
uptime: attributes.resources.uptime,
|
||||
})
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -8,10 +8,12 @@ interface Response {
|
|||
export default (server: string): Promise<Response> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/client/servers/${server}/websocket`)
|
||||
.then(({ data }) => resolve({
|
||||
token: data.data.token,
|
||||
socket: data.data.socket,
|
||||
}))
|
||||
.then(({ data }) =>
|
||||
resolve({
|
||||
token: data.data.token,
|
||||
socket: data.data.socket,
|
||||
})
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Allocation } from '@/api/server/getServer';
|
||||
import http from '@/api/http';
|
||||
|
||||
export default async (uuid: string, id: number): Promise<Allocation> => await http.delete(`/api/client/servers/${uuid}/network/allocations/${id}`);
|
||||
export default async (uuid: string, id: number): Promise<Allocation> =>
|
||||
await http.delete(`/api/client/servers/${uuid}/network/allocations/${id}`);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { rawDataToServerSchedule, Schedule } from '@/api/server/schedules/getServerSchedules';
|
||||
import http from '@/api/http';
|
||||
|
||||
type Data = Pick<Schedule, 'cron' | 'name' | 'onlyWhenOnline' | 'isActive'> & { id?: number }
|
||||
type Data = Pick<Schedule, 'cron' | 'name' | 'onlyWhenOnline' | 'isActive'> & { id?: number };
|
||||
|
||||
export default async (uuid: string, schedule: Data): Promise<Schedule> => {
|
||||
const { data } = await http.post(`/api/client/servers/${uuid}/schedules${schedule.id ? `/${schedule.id}` : ''}`, {
|
||||
|
|
|
@ -9,12 +9,15 @@ interface Data {
|
|||
}
|
||||
|
||||
export default async (uuid: string, schedule: number, task: number | undefined, data: Data): Promise<Task> => {
|
||||
const { data: response } = await http.post(`/api/client/servers/${uuid}/schedules/${schedule}/tasks${task ? `/${task}` : ''}`, {
|
||||
action: data.action,
|
||||
payload: data.payload,
|
||||
continue_on_failure: data.continueOnFailure,
|
||||
time_offset: data.timeOffset,
|
||||
});
|
||||
const { data: response } = await http.post(
|
||||
`/api/client/servers/${uuid}/schedules/${schedule}/tasks${task ? `/${task}` : ''}`,
|
||||
{
|
||||
action: data.action,
|
||||
payload: data.payload,
|
||||
continue_on_failure: data.continueOnFailure,
|
||||
time_offset: data.timeOffset,
|
||||
}
|
||||
);
|
||||
|
||||
return rawDataToServerTask(response.attributes);
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@ export default (uuid: string, schedule: number): Promise<Schedule> => {
|
|||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/client/servers/${uuid}/schedules/${schedule}`, {
|
||||
params: {
|
||||
include: [ 'tasks' ],
|
||||
include: ['tasks'],
|
||||
},
|
||||
})
|
||||
.then(({ data }) => resolve(rawDataToServerSchedule(data.attributes)))
|
||||
|
|
|
@ -69,7 +69,7 @@ export const rawDataToServerSchedule = (data: any): Schedule => ({
|
|||
export default async (uuid: string): Promise<Schedule[]> => {
|
||||
const { data } = await http.get(`/api/client/servers/${uuid}/schedules`, {
|
||||
params: {
|
||||
include: [ 'tasks' ],
|
||||
include: ['tasks'],
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ import http from '@/api/http';
|
|||
import { ServerEggVariable } from '@/api/server/types';
|
||||
import { rawDataToServerEggVariable } from '@/api/transformers';
|
||||
|
||||
export default async (uuid: string, key: string, value: string): Promise<[ ServerEggVariable, string ]> => {
|
||||
export default async (uuid: string, key: string, value: string): Promise<[ServerEggVariable, string]> => {
|
||||
const { data } = await http.put(`/api/client/servers/${uuid}/startup/variable`, { key, value });
|
||||
|
||||
return [ rawDataToServerEggVariable(data), data.meta.startup_command ];
|
||||
return [rawDataToServerEggVariable(data), data.meta.startup_command];
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ export default (uuid: string, params: Params, subuser?: Subuser): Promise<Subuse
|
|||
http.post(`/api/client/servers/${uuid}/users${subuser ? `/${subuser.uuid}` : ''}`, {
|
||||
...params,
|
||||
})
|
||||
.then(data => resolve(rawDataToServerSubuser(data.data)))
|
||||
.then((data) => resolve(rawDataToServerSubuser(data.data)))
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ export const rawDataToServerSubuser = (data: FractalResponseData): Subuser => ({
|
|||
twoFactorEnabled: data.attributes['2fa_enabled'],
|
||||
createdAt: new Date(data.attributes.created_at),
|
||||
permissions: data.attributes.permissions || [],
|
||||
can: permission => (data.attributes.permissions || []).indexOf(permission) >= 0,
|
||||
can: (permission) => (data.attributes.permissions || []).indexOf(permission) >= 0,
|
||||
});
|
||||
|
||||
export default (uuid: string): Promise<Subuser[]> => {
|
||||
|
|
|
@ -5,11 +5,15 @@ import { rawDataToServerAllocation } from '@/api/transformers';
|
|||
import { Allocation } from '@/api/server/getServer';
|
||||
|
||||
export default () => {
|
||||
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
|
||||
const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid);
|
||||
|
||||
return useSWR<Allocation[]>([ 'server:allocations', uuid ], async () => {
|
||||
const { data } = await http.get(`/api/client/servers/${uuid}/network/allocations`);
|
||||
return useSWR<Allocation[]>(
|
||||
['server:allocations', uuid],
|
||||
async () => {
|
||||
const { data } = await http.get(`/api/client/servers/${uuid}/network/allocations`);
|
||||
|
||||
return (data.data || []).map(rawDataToServerAllocation);
|
||||
}, { revalidateOnFocus: false, revalidateOnMount: false });
|
||||
return (data.data || []).map(rawDataToServerAllocation);
|
||||
},
|
||||
{ revalidateOnFocus: false, revalidateOnMount: false }
|
||||
);
|
||||
};
|
||||
|
|
|
@ -16,15 +16,15 @@ type BackupResponse = PaginatedResult<ServerBackup> & { backupCount: number };
|
|||
|
||||
export default () => {
|
||||
const { page } = useContext(Context);
|
||||
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
|
||||
const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid);
|
||||
|
||||
return useSWR<BackupResponse>([ 'server:backups', uuid, page ], async () => {
|
||||
return useSWR<BackupResponse>(['server:backups', uuid, page], async () => {
|
||||
const { data } = await http.get(`/api/client/servers/${uuid}/backups`, { params: { page } });
|
||||
|
||||
return ({
|
||||
return {
|
||||
items: (data.data || []).map(rawDataToServerBackup),
|
||||
pagination: getPaginationSet(data.meta.pagination),
|
||||
backupCount: data.meta.backup_count,
|
||||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
|
|
|
@ -9,14 +9,19 @@ interface Response {
|
|||
dockerImages: Record<string, string>;
|
||||
}
|
||||
|
||||
export default (uuid: string, initialData?: Response | null, config?: ConfigInterface<Response>) => useSWR([ uuid, '/startup' ], async (): Promise<Response> => {
|
||||
const { data } = await http.get(`/api/client/servers/${uuid}/startup`);
|
||||
export default (uuid: string, initialData?: Response | null, config?: ConfigInterface<Response>) =>
|
||||
useSWR(
|
||||
[uuid, '/startup'],
|
||||
async (): Promise<Response> => {
|
||||
const { data } = await http.get(`/api/client/servers/${uuid}/startup`);
|
||||
|
||||
const variables = ((data as FractalResponseList).data || []).map(rawDataToServerEggVariable);
|
||||
const variables = ((data as FractalResponseList).data || []).map(rawDataToServerEggVariable);
|
||||
|
||||
return {
|
||||
variables,
|
||||
invocation: data.meta.startup_command,
|
||||
dockerImages: data.meta.docker_images || {},
|
||||
};
|
||||
}, { initialData: initialData || undefined, errorRetryCount: 3, ...(config || {}) });
|
||||
return {
|
||||
variables,
|
||||
invocation: data.meta.startup_command,
|
||||
dockerImages: data.meta.docker_images || {},
|
||||
};
|
||||
},
|
||||
{ initialData: initialData || undefined, errorRetryCount: 3, ...(config || {}) }
|
||||
);
|
||||
|
|
|
@ -25,33 +25,31 @@ export const rawDataToFileObject = (data: FractalResponseData): FileObject => ({
|
|||
modifiedAt: new Date(data.attributes.modified_at),
|
||||
|
||||
isArchiveType: function () {
|
||||
return this.isFile && [
|
||||
'application/vnd.rar', // .rar
|
||||
'application/x-rar-compressed', // .rar (2)
|
||||
'application/x-tar', // .tar
|
||||
'application/x-br', // .tar.br
|
||||
'application/x-bzip2', // .tar.bz2, .bz2
|
||||
'application/gzip', // .tar.gz, .gz
|
||||
'application/x-gzip',
|
||||
'application/x-lzip', // .tar.lz4, .lz4 (not sure if this mime type is correct)
|
||||
'application/x-sz', // .tar.sz, .sz (not sure if this mime type is correct)
|
||||
'application/x-xz', // .tar.xz, .xz
|
||||
'application/zstd', // .tar.zst, .zst
|
||||
'application/zip', // .zip
|
||||
].indexOf(this.mimetype) >= 0;
|
||||
return (
|
||||
this.isFile &&
|
||||
[
|
||||
'application/vnd.rar', // .rar
|
||||
'application/x-rar-compressed', // .rar (2)
|
||||
'application/x-tar', // .tar
|
||||
'application/x-br', // .tar.br
|
||||
'application/x-bzip2', // .tar.bz2, .bz2
|
||||
'application/gzip', // .tar.gz, .gz
|
||||
'application/x-gzip',
|
||||
'application/x-lzip', // .tar.lz4, .lz4 (not sure if this mime type is correct)
|
||||
'application/x-sz', // .tar.sz, .sz (not sure if this mime type is correct)
|
||||
'application/x-xz', // .tar.xz, .xz
|
||||
'application/zstd', // .tar.zst, .zst
|
||||
'application/zip', // .zip
|
||||
].indexOf(this.mimetype) >= 0
|
||||
);
|
||||
},
|
||||
|
||||
isEditable: function () {
|
||||
if (this.isArchiveType() || !this.isFile) return false;
|
||||
|
||||
const matches = [
|
||||
'application/jar',
|
||||
'application/octet-stream',
|
||||
'inode/directory',
|
||||
/^image\//,
|
||||
];
|
||||
const matches = ['application/jar', 'application/octet-stream', 'inode/directory', /^image\//];
|
||||
|
||||
return matches.every(m => !this.mimetype.match(m));
|
||||
return matches.every((m) => !this.mimetype.match(m));
|
||||
},
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue