diff --git a/resources/scripts/api/account/api-keys.ts b/resources/scripts/api/account/api-keys.ts index 326e2e3b9..eabf84128 100644 --- a/resources/scripts/api/account/api-keys.ts +++ b/resources/scripts/api/account/api-keys.ts @@ -1,7 +1,6 @@ import useSWR, { SWRConfiguration, SWRResponse } from 'swr'; import http, { FractalResponseList } from '@/api/http'; -import Transformers from '@definitions/user/transformers'; -import { PersonalAccessToken } from '@definitions/user/models'; +import { Transformers, PersonalAccessToken } from '@definitions/user'; import { AxiosError } from 'axios'; import useUserSWRContextKey from '@/plugins/useUserSWRContextKey'; @@ -22,7 +21,7 @@ const useAPIKeys = ( const createAPIKey = async (description: string): Promise<[ PersonalAccessToken, string ]> => { const { data } = await http.post('/api/client/account/api-keys', { description }); - const token = Transformers.toPersonalAccessToken(data.attributes); + const token = Transformers.toPersonalAccessToken(data); return [ token, data.meta?.secret_token || '' ]; }; diff --git a/resources/scripts/api/account/security-keys.ts b/resources/scripts/api/account/security-keys.ts index 2f5763cf8..f16bb7a65 100644 --- a/resources/scripts/api/account/security-keys.ts +++ b/resources/scripts/api/account/security-keys.ts @@ -1,7 +1,6 @@ import useSWR, { SWRConfiguration, SWRResponse } from 'swr'; import http, { FractalResponseList } from '@/api/http'; -import Transformers from '@definitions/user/transformers'; -import { SecurityKey } from '@definitions/user/models'; +import { Transformers, SecurityKey } from '@definitions/user'; import { AxiosError } from 'axios'; import { base64Decode, bufferDecode, bufferEncode, decodeSecurityKeyCredentials } from '@/helpers'; import { LoginResponse } from '@/api/auth/login'; @@ -15,7 +14,7 @@ const useSecurityKeys = (config?: SWRConfiguration): async (): Promise => { const { data } = await http.get('/api/client/account/security-keys'); - return (data as FractalResponseList).data.map((datum) => Transformers.toSecurityKey(datum.attributes)); + return (data as FractalResponseList).data.map(Transformers.toSecurityKey); }, config, ); @@ -40,7 +39,7 @@ const registerCredentialForAccount = async (name: string, tokenId: string, crede }, }); - return Transformers.toSecurityKey(data.attributes); + return Transformers.toSecurityKey(data); }; const registerSecurityKey = async (name: string): Promise => { diff --git a/resources/scripts/api/admin/server.ts b/resources/scripts/api/admin/server.ts index ef62c67af..d3fc1e5b1 100644 --- a/resources/scripts/api/admin/server.ts +++ b/resources/scripts/api/admin/server.ts @@ -3,9 +3,8 @@ import { AxiosError } from 'axios'; import { useRouteMatch } from 'react-router-dom'; import http from '@/api/http'; import { Model, UUID, withRelationships, WithRelationships } from '@/api/admin/index'; -import Transformers from '@definitions/admin/transformers'; import { Allocation, Node } from '@/api/admin/node'; -import { User } from '@definitions/admin/models'; +import { Transformers, User } from '@definitions/admin'; import { Egg, EggVariable } from '@/api/admin/egg'; import { Nest } from '@/api/admin/nest'; diff --git a/resources/scripts/api/admin/user.ts b/resources/scripts/api/admin/user.ts index 1b1de004f..2f70e6a3b 100644 --- a/resources/scripts/api/admin/user.ts +++ b/resources/scripts/api/admin/user.ts @@ -1,6 +1,5 @@ import http, { QueryBuilderParams, withQueryBuilderParams } from '@/api/http'; -import Transformers from '@definitions/admin/transformers'; -import { User } from '@definitions/admin/models'; +import { Transformers, User } from '@definitions/admin'; export const getUser = async (id: string | number): Promise => { const { data } = await http.get(`/api/application/users/${id}`); diff --git a/resources/scripts/api/definitions/admin/index.ts b/resources/scripts/api/definitions/admin/index.ts new file mode 100644 index 000000000..39ac1f45a --- /dev/null +++ b/resources/scripts/api/definitions/admin/index.ts @@ -0,0 +1,2 @@ +export * from './models.d'; +export { default as Transformers } from './transformers'; diff --git a/resources/scripts/api/definitions/user/index.ts b/resources/scripts/api/definitions/user/index.ts new file mode 100644 index 000000000..39ac1f45a --- /dev/null +++ b/resources/scripts/api/definitions/user/index.ts @@ -0,0 +1,2 @@ +export * from './models.d'; +export { default as Transformers } from './transformers'; diff --git a/resources/scripts/api/definitions/user/models.d.ts b/resources/scripts/api/definitions/user/models.d.ts index 22b9ce281..70a0cf112 100644 --- a/resources/scripts/api/definitions/user/models.d.ts +++ b/resources/scripts/api/definitions/user/models.d.ts @@ -1,4 +1,5 @@ import { Model, UUID } from '@/api/definitions'; +import { ServerEggVariable, ServerStatus } from '@/api/server/types'; interface SecurityKey extends Model { uuid: UUID; @@ -16,3 +17,46 @@ interface PersonalAccessToken extends Model { updatedAt: Date; lastUsedAt: Date | null; } + +interface Allocation extends Model { + id: number; + ip: string; + alias: string | null; + port: number; + notes: string | null; + isDefault: boolean; +} + +interface Server extends Model { + id: string; + internalId: number | string; + uuid: UUID; + name: string; + node: string; + status: ServerStatus; + sftpDetails: { + ip: string; + port: number; + }; + invocation: string; + dockerImage: string; + description: string; + limits: { + memory: number; + swap: number; + disk: number; + io: number; + cpu: number; + threads: string; + }; + eggFeatures: string[]; + featureLimits: { + databases: number; + allocations: number; + backups: number; + }; + isInstalling: boolean; + isTransferring: boolean; + variables: ServerEggVariable[]; + allocations: Allocation[]; +} diff --git a/resources/scripts/api/definitions/user/transformers.ts b/resources/scripts/api/definitions/user/transformers.ts index 6edf9ce8f..1c1b841dc 100644 --- a/resources/scripts/api/definitions/user/transformers.ts +++ b/resources/scripts/api/definitions/user/transformers.ts @@ -1,24 +1,62 @@ import * as Models from './models'; +import { FractalResponseData, FractalResponseList } from '@/api/http'; +import { rawDataToServerEggVariable } from '@/api/transformers'; export default class Transformers { - static toSecurityKey (data: Record): Models.SecurityKey { + static toSecurityKey ({ attributes }: FractalResponseData): Models.SecurityKey { return { - uuid: data.uuid, - name: data.name, - type: data.type, - publicKeyId: data.public_key_id, - createdAt: new Date(data.created_at), - updatedAt: new Date(data.updated_at), + uuid: attributes.uuid, + name: attributes.name, + type: attributes.type, + publicKeyId: attributes.public_key_id, + createdAt: new Date(attributes.created_at), + updatedAt: new Date(attributes.updated_at), }; } - static toPersonalAccessToken (data: Record): Models.PersonalAccessToken { + static toPersonalAccessToken ({ attributes }: FractalResponseData): Models.PersonalAccessToken { return { - identifier: data.token_id, - description: data.description, - createdAt: new Date(data.created_at), - updatedAt: new Date(data.updated_at), - lastUsedAt: data.last_used_at ? new Date(data.last_used_at) : null, + identifier: attributes.token_id, + description: attributes.description, + createdAt: new Date(attributes.created_at), + updatedAt: new Date(attributes.updated_at), + lastUsedAt: attributes.last_used_at ? new Date(attributes.last_used_at) : null, + }; + } + + static toServerAllocation ({ attributes }: FractalResponseData): Models.Allocation { + return { + id: attributes.id, + ip: attributes.ip, + alias: attributes.ip_alias, + port: attributes.port, + notes: attributes.notes, + isDefault: attributes.is_default, + }; + } + + static toServer ({ attributes }: FractalResponseData): Models.Server { + return { + id: attributes.identifier, + internalId: attributes.internal_id, + uuid: attributes.uuid, + name: attributes.name, + node: attributes.node, + status: attributes.status, + invocation: attributes.invocation, + dockerImage: attributes.docker_image, + sftpDetails: { + ip: attributes.sftp_details.ip, + port: attributes.sftp_details.port, + }, + description: attributes.description ? ((attributes.description.length > 0) ? attributes.description : null) : null, + limits: { ...attributes.limits }, + eggFeatures: attributes.egg_features || [], + featureLimits: { ...attributes.feature_limits }, + isInstalling: attributes.status === 'installing' || attributes.status === 'install_failed', + isTransferring: attributes.is_transferring, + variables: ((attributes.relationships?.variables as FractalResponseList | undefined)?.data || []).map(rawDataToServerEggVariable), + allocations: ((attributes.relationships?.allocations as FractalResponseList | undefined)?.data || []).map(this.toServerAllocation), }; } } diff --git a/resources/scripts/api/getServers.ts b/resources/scripts/api/getServers.ts index 6094b1706..f3b578874 100644 --- a/resources/scripts/api/getServers.ts +++ b/resources/scripts/api/getServers.ts @@ -1,5 +1,5 @@ -import { rawDataToServerObject, Server } from '@/api/server/getServer'; import http, { getPaginationSet, PaginatedResult } from '@/api/http'; +import { Transformers, Server } from '@definitions/user'; interface QueryParams { query?: string; @@ -16,7 +16,7 @@ export default ({ query, ...params }: QueryParams): Promise resolve({ - items: (data.data || []).map((datum: any) => rawDataToServerObject(datum)), + items: (data.data || []).map(Transformers.toServer), pagination: getPaginationSet(data.meta.pagination), })) .catch(reject); diff --git a/resources/scripts/api/server/getServer.ts b/resources/scripts/api/server/getServer.ts index 3d74ee2ab..d89f9eb9b 100644 --- a/resources/scripts/api/server/getServer.ts +++ b/resources/scripts/api/server/getServer.ts @@ -1,81 +1,3 @@ -import http, { FractalResponseData, FractalResponseList } from '@/api/http'; -import { rawDataToServerAllocation, rawDataToServerEggVariable } from '@/api/transformers'; -import { ServerEggVariable, ServerStatus } from '@/api/server/types'; +import * as Models from '@definitions/user/models'; -export interface Allocation { - id: number; - ip: string; - alias: string | null; - port: number; - notes: string | null; - isDefault: boolean; -} - -export interface Server { - id: string; - internalId: number | string; - uuid: string; - name: string; - node: string; - status: ServerStatus; - sftpDetails: { - ip: string; - port: number; - }; - invocation: string; - dockerImage: string; - description: string; - limits: { - memory: number; - swap: number; - disk: number; - io: number; - cpu: number; - threads: string; - }; - eggFeatures: string[]; - featureLimits: { - databases: number; - allocations: number; - backups: number; - }; - isInstalling: boolean; - isTransferring: boolean; - variables: ServerEggVariable[]; - allocations: Allocation[]; -} - -export const rawDataToServerObject = ({ attributes: data }: FractalResponseData): Server => ({ - id: data.identifier, - internalId: data.internal_id, - uuid: data.uuid, - name: data.name, - node: data.node, - status: data.status, - invocation: data.invocation, - dockerImage: data.docker_image, - sftpDetails: { - ip: data.sftp_details.ip, - port: data.sftp_details.port, - }, - description: data.description ? ((data.description.length > 0) ? data.description : null) : null, - limits: { ...data.limits }, - eggFeatures: data.egg_features || [], - featureLimits: { ...data.feature_limits }, - 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), -}); - -export default (uuid: string): Promise<[ Server, string[] ]> => { - return new Promise((resolve, reject) => { - http.get(`/api/client/servers/${uuid}`) - .then(({ data }) => resolve([ - rawDataToServerObject(data), - // eslint-disable-next-line camelcase - data.meta?.is_server_owner ? [ '*' ] : (data.meta?.user_permissions || []), - ])) - .catch(reject); - }); -}; +export type Allocation = Models.Allocation; diff --git a/resources/scripts/api/server/index.ts b/resources/scripts/api/server/index.ts new file mode 100644 index 000000000..e8bc5f116 --- /dev/null +++ b/resources/scripts/api/server/index.ts @@ -0,0 +1,14 @@ +import http from '@/api/http'; +import { Transformers, Server } from '@definitions/user'; + +const getServer = async (uuid: string): Promise<[ Server, string[] ]> => { + const { data } = await http.get(`/api/client/servers/${uuid}`); + + return [ + Transformers.toServer(data), + // eslint-disable-next-line camelcase + data.meta?.is_server_owner ? [ '*' ] : (data.meta?.user_permissions || []), + ]; +}; + +export { getServer }; diff --git a/resources/scripts/components/admin/servers/OwnerSelect.tsx b/resources/scripts/components/admin/servers/OwnerSelect.tsx index 8cc8a1647..022e5b593 100644 --- a/resources/scripts/components/admin/servers/OwnerSelect.tsx +++ b/resources/scripts/components/admin/servers/OwnerSelect.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { useFormikContext } from 'formik'; import SearchableSelect, { Option } from '@/components/elements/SearchableSelect'; -import { User } from '@definitions/admin/models'; +import { User } from '@definitions/admin'; import { searchUserAccounts } from '@/api/admin/user'; export default ({ selected }: { selected?: User }) => { diff --git a/resources/scripts/components/admin/users/UserTableRow.tsx b/resources/scripts/components/admin/users/UserTableRow.tsx index 10c87a48a..d076f2ded 100644 --- a/resources/scripts/components/admin/users/UserTableRow.tsx +++ b/resources/scripts/components/admin/users/UserTableRow.tsx @@ -2,7 +2,7 @@ import { Checkbox } from '@/components/elements/inputs'; import { Dropdown } from '@/components/elements/dropdown'; import { BanIcon, DotsVerticalIcon, LockOpenIcon, PencilIcon, SupportIcon, TrashIcon } from '@heroicons/react/solid'; import React, { useState } from 'react'; -import { User } from '@definitions/admin/models'; +import { User } from '@definitions/admin'; import { Dialog } from '@/components/elements/dialog'; import { Button } from '@/components/elements/button/index'; diff --git a/resources/scripts/components/admin/users/UsersContainerV2.tsx b/resources/scripts/components/admin/users/UsersContainerV2.tsx index f5c9b4b37..cd010ac5b 100644 --- a/resources/scripts/components/admin/users/UsersContainerV2.tsx +++ b/resources/scripts/components/admin/users/UsersContainerV2.tsx @@ -1,7 +1,6 @@ import React, { useEffect, useState } from 'react'; import http from '@/api/http'; -import { User } from '@definitions/admin/models'; -import Transformers from '@definitions/admin/transformers'; +import { Transformers, User } from '@definitions/admin'; import { LockOpenIcon, PlusIcon, SupportIcon, TrashIcon } from '@heroicons/react/solid'; import { Button } from '@/components/elements/button/index'; import { Checkbox, InputField } from '@/components/elements/inputs'; diff --git a/resources/scripts/components/dashboard/DashboardContainer.tsx b/resources/scripts/components/dashboard/DashboardContainer.tsx index 7c9d266c2..b96f6e93e 100644 --- a/resources/scripts/components/dashboard/DashboardContainer.tsx +++ b/resources/scripts/components/dashboard/DashboardContainer.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { Server } from '@/api/server/getServer'; +import { Server } from '@definitions/user'; import getServers from '@/api/getServers'; import ServerRow from '@/components/dashboard/ServerRow'; import Spinner from '@/components/elements/Spinner'; diff --git a/resources/scripts/components/dashboard/ServerRow.tsx b/resources/scripts/components/dashboard/ServerRow.tsx index 60922df06..68c0b9d4f 100644 --- a/resources/scripts/components/dashboard/ServerRow.tsx +++ b/resources/scripts/components/dashboard/ServerRow.tsx @@ -2,7 +2,7 @@ import React, { memo, useEffect, useRef, useState } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faEthernet, faHdd, faMemory, faMicrochip, faServer } from '@fortawesome/free-solid-svg-icons'; import { Link } from 'react-router-dom'; -import { Server } from '@/api/server/getServer'; +import { Server } from '@definitions/user'; import getServerResourceUsage, { ServerPowerState, ServerStats } from '@/api/server/getServerResourceUsage'; import { bytesToHuman, megabytesToHuman, formatIp } from '@/helpers'; import tw, { styled } from 'twin.macro'; diff --git a/resources/scripts/components/dashboard/search/SearchModal.tsx b/resources/scripts/components/dashboard/search/SearchModal.tsx index c7ce58008..700c613e0 100644 --- a/resources/scripts/components/dashboard/search/SearchModal.tsx +++ b/resources/scripts/components/dashboard/search/SearchModal.tsx @@ -7,7 +7,7 @@ import debounce from 'debounce'; import FormikFieldWrapper from '@/components/elements/FormikFieldWrapper'; import InputSpinner from '@/components/elements/InputSpinner'; import getServers from '@/api/getServers'; -import { Server } from '@/api/server/getServer'; +import { Server } from '@definitions/user'; import { ApplicationStore } from '@/state'; import { Link } from 'react-router-dom'; import tw, { styled } from 'twin.macro'; diff --git a/resources/scripts/components/dashboard/security/AddSecurityKeyForm.tsx b/resources/scripts/components/dashboard/security/AddSecurityKeyForm.tsx index 8f7dc822f..4abb515d2 100644 --- a/resources/scripts/components/dashboard/security/AddSecurityKeyForm.tsx +++ b/resources/scripts/components/dashboard/security/AddSecurityKeyForm.tsx @@ -1,4 +1,4 @@ -import { SecurityKey } from '@definitions/user/models'; +import { SecurityKey } from '@definitions/user'; import { useFlashKey } from '@/plugins/useFlash'; import { Form, Formik, FormikHelpers } from 'formik'; import { registerSecurityKey } from '@/api/account/security-keys'; diff --git a/resources/scripts/state/server/index.ts b/resources/scripts/state/server/index.ts index 9a2be5541..48f073b32 100644 --- a/resources/scripts/state/server/index.ts +++ b/resources/scripts/state/server/index.ts @@ -1,4 +1,4 @@ -import getServer, { Server } from '@/api/server/getServer'; +import { getServer } from '@/api/server'; import { action, Action, computed, Computed, createContextStore, thunk, Thunk } from 'easy-peasy'; import socket, { SocketStore } from './socket'; import files, { ServerFileStore } from '@/state/server/files'; @@ -7,6 +7,7 @@ import { composeWithDevTools } from 'redux-devtools-extension'; import schedules, { ServerScheduleStore } from '@/state/server/schedules'; import databases, { ServerDatabaseStore } from '@/state/server/databases'; import isEqual from 'react-fast-compare'; +import { Server } from '@definitions/user'; export type ServerStatus = 'offline' | 'starting' | 'stopping' | 'running' | null;