mirror of
https://github.com/pyrohost/pyrodactyl.git
synced 2026-04-06 04:01:58 +02:00
feat: make linting functional + lint pass
This commit is contained in:
@@ -3,6 +3,7 @@ module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
parserOptions: {
|
||||
ecmaVersion: 6,
|
||||
ecmaFeatures: {
|
||||
@@ -26,6 +27,7 @@ module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
node: true,
|
||||
},
|
||||
plugins: ['react', 'react-hooks', 'prettier', '@typescript-eslint'],
|
||||
extends: [
|
||||
@@ -36,9 +38,10 @@ module.exports = {
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
],
|
||||
rules: {
|
||||
eqeqeq: 'error',
|
||||
'@typescript-eslint/no-var-requires': 0,
|
||||
'@typescript-eslint/ban-ts-comment': 0,
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
'warn',
|
||||
{
|
||||
endOfLine: 'auto',
|
||||
},
|
||||
@@ -57,6 +60,5 @@ module.exports = {
|
||||
'no-use-before-define': 0,
|
||||
'@typescript-eslint/no-use-before-define': 'warn',
|
||||
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
|
||||
'@typescript-eslint/ban-ts-comment': ['error', { 'ts-expect-error': 'allow-with-description' }],
|
||||
},
|
||||
};
|
||||
|
||||
55
package-lock.json
generated
55
package-lock.json
generated
@@ -78,10 +78,10 @@
|
||||
"autoprefixer": "^10.4.7",
|
||||
"babel-plugin-styled-components": "^2.1.4",
|
||||
"cross-env": "^7.0.2",
|
||||
"eslint": "^8.18.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-react": "^7.30.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"postcss": "^8.4.38",
|
||||
@@ -2262,6 +2262,18 @@
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgr/core": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz",
|
||||
"integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/unts"
|
||||
}
|
||||
},
|
||||
"node_modules/@preact/signals-core": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.6.0.tgz",
|
||||
@@ -5410,21 +5422,30 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-prettier": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
|
||||
"integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz",
|
||||
"integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"prettier-linter-helpers": "^1.0.0"
|
||||
"prettier-linter-helpers": "^1.0.0",
|
||||
"synckit": "^0.8.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
"node": "^14.18.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint-plugin-prettier"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=7.28.0",
|
||||
"prettier": ">=2.0.0"
|
||||
"@types/eslint": ">=8.0.0",
|
||||
"eslint": ">=8.0.0",
|
||||
"eslint-config-prettier": "*",
|
||||
"prettier": ">=3.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/eslint": {
|
||||
"optional": true
|
||||
},
|
||||
"eslint-config-prettier": {
|
||||
"optional": true
|
||||
}
|
||||
@@ -9114,6 +9135,22 @@
|
||||
"react": "^16.11.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/synckit": {
|
||||
"version": "0.8.8",
|
||||
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz",
|
||||
"integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@pkgr/core": "^0.1.0",
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/unts"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwind-merge": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.2.tgz",
|
||||
|
||||
@@ -77,10 +77,10 @@
|
||||
"autoprefixer": "^10.4.7",
|
||||
"babel-plugin-styled-components": "^2.1.4",
|
||||
"cross-env": "^7.0.2",
|
||||
"eslint": "^8.18.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-react": "^7.30.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"postcss": "^8.4.38",
|
||||
|
||||
@@ -12,7 +12,7 @@ export type ActivityLogFilters = QueryBuilderParams<'ip' | 'event', 'timestamp'>
|
||||
|
||||
const useActivityLogs = (
|
||||
filters?: ActivityLogFilters,
|
||||
config?: SWRConfiguration<PaginatedResult<ActivityLog>, AxiosError>
|
||||
config?: SWRConfiguration<PaginatedResult<ActivityLog>, AxiosError>,
|
||||
) => {
|
||||
const key = useUserSWRKey(['account', 'activity', JSON.stringify(useFilteredObject(filters || {}))]);
|
||||
|
||||
@@ -28,7 +28,7 @@ const useActivityLogs = (
|
||||
|
||||
return toPaginatedSet(data, Transformers.toActivityLog);
|
||||
},
|
||||
{ revalidateOnMount: false, ...(config || {}) }
|
||||
{ revalidateOnMount: false, ...(config || {}) },
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ export default (description: string, allowedIps: string): Promise<ApiKey & { sec
|
||||
...rawDataToApiKey(data.attributes),
|
||||
// eslint-disable-next-line camelcase
|
||||
secretToken: data.meta?.secret_token ?? '',
|
||||
})
|
||||
}),
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
@@ -18,7 +18,7 @@ const useSSHKeys = (config?: SWRConfiguration<SSHKey[], AxiosError>) => {
|
||||
return Transformers.toSSHKey(datum.attributes);
|
||||
});
|
||||
},
|
||||
{ revalidateOnMount: false, ...(config || {}) }
|
||||
{ revalidateOnMount: false, ...(config || {}) },
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ export default ({ username, password, recaptchaData }: LoginData): Promise<Login
|
||||
user: username,
|
||||
password,
|
||||
'g-recaptcha-response': recaptchaData,
|
||||
})
|
||||
}),
|
||||
)
|
||||
.then((response) => {
|
||||
if (!(response.data instanceof Object)) {
|
||||
|
||||
@@ -12,7 +12,7 @@ export default (token: string, code: string, recoveryToken?: string): Promise<Lo
|
||||
resolve({
|
||||
complete: response.data.data.complete,
|
||||
intended: response.data.data.intended || undefined,
|
||||
})
|
||||
}),
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@ export default (email: string, data: Data): Promise<PasswordResetResponse> => {
|
||||
resolve({
|
||||
redirectTo: response.data.redirect_to,
|
||||
sendToLogin: response.data.send_to_login,
|
||||
})
|
||||
}),
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
@@ -15,17 +15,17 @@ function transform<T, M>(data: null | undefined, transformer: TransformerFunc<T>
|
||||
function transform<T, M>(
|
||||
data: FractalResponseData | null | undefined,
|
||||
transformer: TransformerFunc<T>,
|
||||
missing?: M
|
||||
missing?: M,
|
||||
): T | M;
|
||||
function transform<T, M>(
|
||||
data: FractalResponseList | FractalPaginatedResponse | null | undefined,
|
||||
transformer: TransformerFunc<T>,
|
||||
missing?: M
|
||||
missing?: M,
|
||||
): T[] | M;
|
||||
function transform<T>(
|
||||
data: FractalResponseData | FractalResponseList | FractalPaginatedResponse | null | undefined,
|
||||
transformer: TransformerFunc<T>,
|
||||
missing = undefined
|
||||
missing = undefined,
|
||||
) {
|
||||
if (data === undefined || data === null) {
|
||||
return missing;
|
||||
@@ -44,7 +44,7 @@ function transform<T>(
|
||||
|
||||
function toPaginatedSet<T extends TransformerFunc<Model>>(
|
||||
response: FractalPaginatedResponse,
|
||||
transformer: T
|
||||
transformer: T,
|
||||
): PaginatedResult<ReturnType<T>> {
|
||||
return {
|
||||
items: transform(response, transformer) as ReturnType<T>[],
|
||||
|
||||
@@ -19,7 +19,7 @@ export default ({ query, ...params }: QueryParams): Promise<PaginatedResult<Serv
|
||||
resolve({
|
||||
items: (data.data || []).map((datum: any) => rawDataToServerObject(datum)),
|
||||
pagination: getPaginationSet(data.meta.pagination),
|
||||
})
|
||||
}),
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ http.interceptors.response.use(
|
||||
store.getActions().progress.setComplete();
|
||||
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export default http;
|
||||
@@ -137,11 +137,14 @@ export interface QueryBuilderParams<FilterKeys extends string = string, SortKeys
|
||||
export const withQueryBuilderParams = (data?: QueryBuilderParams): Record<string, unknown> => {
|
||||
if (!data) return {};
|
||||
|
||||
const filters = Object.keys(data.filters || {}).reduce((obj, key) => {
|
||||
const value = data.filters?.[key];
|
||||
const filters = Object.keys(data.filters || {}).reduce(
|
||||
(obj, key) => {
|
||||
const value = data.filters?.[key];
|
||||
|
||||
return !value || value === '' ? obj : { ...obj, [`filter[${key}]`]: value };
|
||||
}, {} as NonNullable<QueryBuilderParams['filters']>);
|
||||
return !value || value === '' ? obj : { ...obj, [`filter[${key}]`]: value };
|
||||
},
|
||||
{} as NonNullable<QueryBuilderParams['filters']>,
|
||||
);
|
||||
|
||||
const sorts = Object.keys(data.sorts || {}).reduce((arr, key) => {
|
||||
const value = data.sorts?.[key];
|
||||
|
||||
@@ -5,7 +5,7 @@ import http from '@/api/http';
|
||||
|
||||
export const setupInterceptors = (navigate: NavigateFunction) => {
|
||||
http.interceptors.response.use(
|
||||
resp => resp,
|
||||
(resp) => resp,
|
||||
(error: AxiosError) => {
|
||||
if (error.response?.status === 400) {
|
||||
if (
|
||||
@@ -19,4 +19,4 @@ export const setupInterceptors = (navigate: NavigateFunction) => {
|
||||
throw error;
|
||||
},
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ export type ActivityLogFilters = QueryBuilderParams<'ip' | 'event', 'timestamp'>
|
||||
|
||||
const useActivityLogs = (
|
||||
filters?: ActivityLogFilters,
|
||||
config?: SWRConfiguration<PaginatedResult<ActivityLog>, AxiosError>
|
||||
config?: SWRConfiguration<PaginatedResult<ActivityLog>, AxiosError>,
|
||||
) => {
|
||||
const uuid = ServerContext.useStoreState((state) => state.server.data?.uuid);
|
||||
const key = useServerSWRKey(['activity', useFilteredObject(filters || {})]);
|
||||
@@ -32,7 +32,7 @@ const useActivityLogs = (
|
||||
|
||||
return toPaginatedSet(data, Transformers.toActivityLog);
|
||||
},
|
||||
{ revalidateOnMount: false, ...(config || {}) }
|
||||
{ revalidateOnMount: false, ...(config || {}) },
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ export default (uuid: string, data: { connectionsFrom: string; databaseName: str
|
||||
},
|
||||
{
|
||||
params: { include: 'password' },
|
||||
}
|
||||
},
|
||||
)
|
||||
.then((response) => resolve(rawDataToServerDatabase(response.data.attributes)))
|
||||
.catch(reject);
|
||||
|
||||
@@ -24,7 +24,7 @@ export default (uuid: string, includePassword = true): Promise<ServerDatabase[]>
|
||||
params: includePassword ? { include: 'password' } : undefined,
|
||||
})
|
||||
.then((response) =>
|
||||
resolve((response.data.data || []).map((item: any) => rawDataToServerDatabase(item.attributes)))
|
||||
resolve((response.data.data || []).map((item: any) => rawDataToServerDatabase(item.attributes))),
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ export default async (uuid: string, directory: string, files: string[]): Promise
|
||||
timeout: 60000,
|
||||
timeoutErrorMessage:
|
||||
'It looks like this archive is taking a long time to generate. It will appear once completed.',
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return rawDataToFileObject(data);
|
||||
|
||||
@@ -8,6 +8,6 @@ export default async (uuid: string, directory: string, file: string): Promise<vo
|
||||
timeout: 300000,
|
||||
timeoutErrorMessage:
|
||||
'It looks like this archive is taking a long time to be unarchived. Once completed the unarchived files will appear.',
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -65,10 +65,10 @@ export const rawDataToServerObject = ({ attributes: data }: FractalResponseData)
|
||||
featureLimits: { ...data.feature_limits },
|
||||
isTransferring: data.is_transferring,
|
||||
variables: ((data.relationships?.variables as FractalResponseList | undefined)?.data || []).map(
|
||||
rawDataToServerEggVariable
|
||||
rawDataToServerEggVariable,
|
||||
),
|
||||
allocations: ((data.relationships?.allocations as FractalResponseList | undefined)?.data || []).map(
|
||||
rawDataToServerAllocation
|
||||
rawDataToServerAllocation,
|
||||
),
|
||||
});
|
||||
|
||||
@@ -80,7 +80,7 @@ export default (uuid: string): Promise<[Server, string[]]> => {
|
||||
rawDataToServerObject(data),
|
||||
// eslint-disable-next-line camelcase
|
||||
data.meta?.is_server_owner ? ['*'] : data.meta?.user_permissions || [],
|
||||
])
|
||||
]),
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
@@ -26,7 +26,7 @@ export default (server: string): Promise<ServerStats> => {
|
||||
networkRxInBytes: attributes.resources.network_rx_bytes,
|
||||
networkTxInBytes: attributes.resources.network_tx_bytes,
|
||||
uptime: attributes.resources.uptime,
|
||||
})
|
||||
}),
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ export default (server: string): Promise<Response> => {
|
||||
resolve({
|
||||
token: data.data.token,
|
||||
socket: data.data.socket,
|
||||
})
|
||||
}),
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ export default async (uuid: string, schedule: number, task: number | undefined,
|
||||
payload: data.payload,
|
||||
continue_on_failure: data.continueOnFailure,
|
||||
time_offset: data.timeOffset,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return rawDataToServerTask(response.attributes);
|
||||
|
||||
@@ -15,6 +15,6 @@ export default () => {
|
||||
|
||||
return (data.data || []).map(rawDataToServerAllocation);
|
||||
},
|
||||
{ revalidateOnFocus: false, revalidateOnMount: false }
|
||||
{ revalidateOnFocus: false, revalidateOnMount: false },
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -29,4 +29,4 @@ export default () => {
|
||||
backupCount: data.meta.backup_count,
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
@@ -26,5 +26,5 @@ export default (uuid: string, fallbackData?: Response, config?: SWRConfiguration
|
||||
dockerImages: data.meta.docker_images || {},
|
||||
};
|
||||
},
|
||||
{ fallbackData, errorRetryCount: 3, ...(config ?? {}) }
|
||||
{ fallbackData, errorRetryCount: 3, ...(config ?? {}) },
|
||||
);
|
||||
|
||||
@@ -4,12 +4,11 @@ import { Fragment } from 'react';
|
||||
|
||||
type Props = Readonly<{
|
||||
byKey?: string;
|
||||
className?: string;
|
||||
}>;
|
||||
|
||||
const FlashMessageRender = ({ byKey, className }: Props) => {
|
||||
const FlashMessageRender = ({ byKey }: Props) => {
|
||||
const flashes = useStoreState((state) =>
|
||||
state.flashes.items.filter((flash) => (byKey ? flash.key === byKey : true))
|
||||
state.flashes.items.filter((flash) => (byKey ? flash.key === byKey : true)),
|
||||
);
|
||||
|
||||
return flashes.length ? (
|
||||
|
||||
@@ -89,7 +89,7 @@ export default () => {
|
||||
/>
|
||||
</div>
|
||||
<h2 className='text-xl font-extrabold mb-2'>Reset Password</h2>
|
||||
<div className='text-sm mb-6'>We'll send you an email with a link to reset your password.</div>
|
||||
<div className='text-sm mb-6'>We'll send you an email with a link to reset your password.</div>
|
||||
<Field id='email' label={'Email'} name={'email'} type={'email'} />
|
||||
<div className={`mt-6`}>
|
||||
<Button
|
||||
|
||||
@@ -30,7 +30,6 @@ function LoginCheckpointContainer() {
|
||||
<LoginFormContainer title={'Device Checkpoint'} className={`w-full flex`}>
|
||||
<div className={`mt-6`}>
|
||||
<Field
|
||||
light
|
||||
name={isMissingDevice ? 'recoveryCode' : 'code'}
|
||||
title={isMissingDevice ? 'Recovery Code' : 'Authentication Code'}
|
||||
description={
|
||||
|
||||
@@ -61,10 +61,8 @@ export default () => {
|
||||
{loading ? 'Loading...' : 'No API keys exist for this account.'}
|
||||
</p>
|
||||
) : (
|
||||
keys.map((key, index) => (
|
||||
<GreyRowBox
|
||||
key={key.identifier}
|
||||
>
|
||||
keys.map((key, _) => (
|
||||
<GreyRowBox key={key.identifier}>
|
||||
{/* <FontAwesomeIcon icon={faKey} className={`text-zinc-300`} /> */}
|
||||
<div className={`ml-4 flex-1 overflow-hidden`}>
|
||||
<p className={`text-sm break-words`}>{key.description}</p>
|
||||
@@ -76,7 +74,10 @@ export default () => {
|
||||
<p className={`text-sm ml-4 hidden md:block`}>
|
||||
<code className={`font-mono py-1 px-2 bg-zinc-900 rounded`}>{key.identifier}</code>
|
||||
</p>
|
||||
<button className={`ml-4 p-2 text-sm`} onClick={() => setDeleteIdentifier(key.identifier)}>
|
||||
<button
|
||||
className={`ml-4 p-2 text-sm`}
|
||||
onClick={() => setDeleteIdentifier(key.identifier)}
|
||||
>
|
||||
{/* <FontAwesomeIcon
|
||||
icon={faTrashAlt}
|
||||
className={`text-zinc-400 hover:text-red-400 transition-colors duration-150`}
|
||||
|
||||
@@ -40,15 +40,15 @@ const StatusIndicatorBox = styled.div<{ $status: ServerPowerState | undefined }>
|
||||
!$status || $status === 'offline'
|
||||
? '0 0 12px 1px #C74343'
|
||||
: $status === 'running'
|
||||
? '0 0 12px 1px #43C760'
|
||||
: '0 0 12px 1px #c7aa43'};
|
||||
? '0 0 12px 1px #43C760'
|
||||
: '0 0 12px 1px #c7aa43'};
|
||||
|
||||
background: ${({ $status }) =>
|
||||
!$status || $status === 'offline'
|
||||
? `linear-gradient(180deg, #C74343 0%, #C74343 100%)`
|
||||
: $status === 'running'
|
||||
? `linear-gradient(180deg, #91FFA9 0%, #43C760 100%)`
|
||||
: `linear-gradient(180deg, #c7aa43 0%, #c7aa43 100%)`};
|
||||
? `linear-gradient(180deg, #91FFA9 0%, #43C760 100%)`
|
||||
: `linear-gradient(180deg, #c7aa43 0%, #c7aa43 100%)`};
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -133,10 +133,10 @@ export default ({ server, className }: { server: Server; className?: string }) =
|
||||
{server.isTransferring
|
||||
? 'Transferring'
|
||||
: server.status === 'installing'
|
||||
? 'Installing'
|
||||
: server.status === 'restoring_backup'
|
||||
? 'Restoring Backup'
|
||||
: 'Unavailable'}
|
||||
? 'Installing'
|
||||
: server.status === 'restoring_backup'
|
||||
? 'Restoring Backup'
|
||||
: 'Unavailable'}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
|
||||
@@ -9,7 +9,7 @@ import { httpErrorToHuman } from '@/api/http';
|
||||
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
|
||||
import { ApiKey } from '@/api/account/getApiKeys';
|
||||
import Button from '@/components/elements/Button';
|
||||
import Input, { Textarea } from '@/components/elements/Input';
|
||||
import Input from '@/components/elements/Input';
|
||||
import ApiKeyModal from '@/components/dashboard/ApiKeyModal';
|
||||
|
||||
interface Values {
|
||||
|
||||
@@ -40,7 +40,7 @@ const DisableTOTPDialog = () => {
|
||||
|
||||
return (
|
||||
<form id={'disable-totp-form'} className={'mt-6'} onSubmit={submit}>
|
||||
<FlashMessageRender byKey={'account:two-step'} className={'-mt-2 mb-6'} />
|
||||
<FlashMessageRender byKey={'account:two-step'} />
|
||||
<label className={'block pb-1'} htmlFor={'totp-password'}>
|
||||
Password
|
||||
</label>
|
||||
|
||||
@@ -60,7 +60,7 @@ const ConfigureTwoFactorForm = ({ onTokens }: Props) => {
|
||||
|
||||
return (
|
||||
<form id={'enable-totp-form'} onSubmit={submit}>
|
||||
<FlashMessageRender byKey={'account:two-step'} className={'mt-4'} />
|
||||
<FlashMessageRender byKey={'account:two-step'} />
|
||||
<div className={'flex items-center justify-center w-56 h-56 p-2 bg-zinc-50 shadow mx-auto mt-6'}>
|
||||
{!token ? (
|
||||
<Spinner />
|
||||
|
||||
@@ -33,7 +33,7 @@ export default () => {
|
||||
type: 'success',
|
||||
key: 'account:email',
|
||||
message: 'Your primary email has been updated.',
|
||||
})
|
||||
}),
|
||||
)
|
||||
.catch((error) =>
|
||||
addFlash({
|
||||
@@ -41,7 +41,7 @@ export default () => {
|
||||
key: 'account:email',
|
||||
title: 'Error',
|
||||
message: httpErrorToHuman(error),
|
||||
})
|
||||
}),
|
||||
)
|
||||
.then(() => {
|
||||
resetForm();
|
||||
|
||||
@@ -7,7 +7,7 @@ import updateAccountPassword from '@/api/account/updateAccountPassword';
|
||||
import { httpErrorToHuman } from '@/api/http';
|
||||
import { ApplicationStore } from '@/state';
|
||||
import { Button } from '@/components/elements/button/index';
|
||||
import { Fragment } from 'react'
|
||||
import { Fragment } from 'react';
|
||||
|
||||
interface Values {
|
||||
current: string;
|
||||
@@ -23,7 +23,7 @@ const schema = Yup.object().shape({
|
||||
'Password confirmation does not match the password you entered.',
|
||||
function (value) {
|
||||
return value === this.parent.password;
|
||||
}
|
||||
},
|
||||
),
|
||||
});
|
||||
|
||||
@@ -48,7 +48,7 @@ export default () => {
|
||||
type: 'error',
|
||||
title: 'Error',
|
||||
message: httpErrorToHuman(error),
|
||||
})
|
||||
}),
|
||||
)
|
||||
.then(() => setSubmitting(false));
|
||||
};
|
||||
|
||||
@@ -35,10 +35,8 @@ export default () => {
|
||||
{!data ? 'Loading...' : 'No SSH Keys exist for this account.'}
|
||||
</p>
|
||||
) : (
|
||||
data.map((key, index) => (
|
||||
<GreyRowBox
|
||||
key={key.fingerprint}
|
||||
>
|
||||
data.map((key, _) => (
|
||||
<GreyRowBox key={key.fingerprint}>
|
||||
{/* <FontAwesomeIcon icon={faKey} className={`text-zinc-300`} /> */}
|
||||
<div className={`flex-1`}>
|
||||
<p className={`text-sm break-words font-medium`}>{key.name}</p>
|
||||
|
||||
@@ -3,8 +3,7 @@ import { object, string } from 'yup';
|
||||
import FormikFieldWrapper from '@/components/elements/FormikFieldWrapper';
|
||||
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
|
||||
import Button from '@/components/elements/Button';
|
||||
import Input, { Textarea } from '@/components/elements/Input';
|
||||
import styled from 'styled-components';
|
||||
import Input from '@/components/elements/Input';
|
||||
import { useFlashKey } from '@/plugins/useFlash';
|
||||
import { createSSHKey, useSSHKeys } from '@/api/account/ssh-keys';
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ type Props = Readonly<
|
||||
}
|
||||
>;
|
||||
|
||||
const ContentBox = ({ title, borderColor, showFlashes, showLoadingOverlay, children, ...props }: Props) => (
|
||||
const ContentBox = ({ title, showFlashes, showLoadingOverlay, children, ...props }: Props) => (
|
||||
<div className='p-8 bg-[#ffffff09] border-[1px] border-[#ffffff11] shadow-sm rounded-xl' {...props}>
|
||||
{title && <h2 className={`font-extrabold mb-4 text-2xl`}>{title}</h2>}
|
||||
{showFlashes && <FlashMessageRender byKey={typeof showFlashes === 'string' ? showFlashes : undefined} />}
|
||||
|
||||
@@ -27,7 +27,7 @@ const ContextMenuSubTrigger = React.forwardRef<
|
||||
className={cn(
|
||||
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground',
|
||||
inset && 'pl-8',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
@@ -45,7 +45,7 @@ const ContextMenuSubContent = React.forwardRef<
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'z-50 min-w-[14rem] overflow-hidden rounded-xl bg-[#ffffff22] backdrop-blur-2xl p-2 shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -61,7 +61,7 @@ const ContextMenuContent = React.forwardRef<
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'z-50 min-w-[14rem] overflow-hidden rounded-xl bg-[#ffffff22] backdrop-blur-2xl p-2 shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -80,7 +80,7 @@ const ContextMenuItem = React.forwardRef<
|
||||
className={cn(
|
||||
'font-bold relative flex cursor-default select-none items-center rounded-lg px-2 py-1.5 text-sm outline-none focus:bg-[#ffffff33] data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
inset && 'pl-8',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -95,7 +95,7 @@ const ContextMenuCheckboxItem = React.forwardRef<
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
@@ -118,7 +118,7 @@ const ContextMenuRadioItem = React.forwardRef<
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
||||
@@ -27,7 +27,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
|
||||
className={cn(
|
||||
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent',
|
||||
inset && 'pl-8',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
@@ -45,7 +45,7 @@ const DropdownMenuSubContent = React.forwardRef<
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'z-50 min-w-[14rem] overflow-hidden rounded-xl bg-[#ffffff22] backdrop-blur-2xl p-2 shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -63,7 +63,7 @@ const DropdownMenuContent = React.forwardRef<
|
||||
className={cn(
|
||||
'z-50 min-w-[14rem] overflow-hidden rounded-xl bg-[#ffffff22] backdrop-blur-2xl p-2 shadow-md',
|
||||
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -82,7 +82,7 @@ const DropdownMenuItem = React.forwardRef<
|
||||
className={cn(
|
||||
'font-bold relative flex cursor-default select-none items-center rounded-lg px-2 py-1.5 text-sm outline-none transition-colors focus:bg-[#ffffff33] data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
inset && 'pl-8',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -97,7 +97,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
@@ -120,7 +120,7 @@ const DropdownMenuRadioItem = React.forwardRef<
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
||||
@@ -3,7 +3,6 @@ import { Field as FormikField, FieldProps } from 'formik';
|
||||
|
||||
interface OwnProps {
|
||||
name: string;
|
||||
light?: boolean;
|
||||
label?: string;
|
||||
description?: string;
|
||||
validate?: (value: any) => undefined | string | Promise<any>;
|
||||
@@ -12,7 +11,7 @@ interface OwnProps {
|
||||
type Props = OwnProps & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'name'>;
|
||||
|
||||
const Field = forwardRef<HTMLInputElement, Props>(
|
||||
({ id, name, light = false, label, description, validate, ...props }, ref) => (
|
||||
({ id, name = false, label, description, validate, ...props }, ref) => (
|
||||
<FormikField innerRef={ref} name={name} validate={validate}>
|
||||
{({ field, form: { errors, touched } }: FieldProps) => (
|
||||
<div className='flex flex-col gap-2'>
|
||||
@@ -38,7 +37,7 @@ const Field = forwardRef<HTMLInputElement, Props>(
|
||||
</div>
|
||||
)}
|
||||
</FormikField>
|
||||
)
|
||||
),
|
||||
);
|
||||
Field.displayName = 'Field';
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
const Icon = () => {
|
||||
return (
|
||||
<div>This component is deprecated.</div>
|
||||
);
|
||||
return <div>This component is deprecated.</div>;
|
||||
};
|
||||
|
||||
export default Icon;
|
||||
|
||||
@@ -8,17 +8,17 @@ export interface Props {
|
||||
const checkboxStyle = css<Props>`
|
||||
color-adjust: exact;
|
||||
background-origin: border-box;
|
||||
transition: all 75ms linear, box-shadow 25ms linear;
|
||||
transition:
|
||||
all 75ms linear,
|
||||
box-shadow 25ms linear;
|
||||
|
||||
&:checked {
|
||||
|
||||
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='black' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M5.707 7.293a1 1 0 0 0-1.414 1.414l2 2a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0-1.414-1.414L7 8.586 5.707 7.293z'/%3e%3c/svg%3e");
|
||||
background-color: white;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
|
||||
box-shadow: 0 0 0 1px rgba(9, 103, 210, 0.25);
|
||||
}
|
||||
`;
|
||||
@@ -28,12 +28,10 @@ const inputStyle = css<Props>`
|
||||
resize: none;
|
||||
|
||||
& + .input-help {
|
||||
|
||||
}
|
||||
|
||||
&:required,
|
||||
&:invalid {
|
||||
|
||||
}
|
||||
|
||||
&:not(:disabled):not(:read-only):focus {
|
||||
@@ -53,7 +51,6 @@ const Input = styled.input<Props>`
|
||||
${checkboxStyle};
|
||||
|
||||
&[type='radio'] {
|
||||
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import Spinner from '@/components/elements/Spinner';
|
||||
import styled from 'styled-components';
|
||||
|
||||
@@ -16,7 +16,7 @@ interface Props<T> {
|
||||
children: (props: RenderFuncProps<T>) => React.ReactNode;
|
||||
}
|
||||
|
||||
const Block = styled(Button)``
|
||||
const Block = styled(Button)``;
|
||||
|
||||
function Pagination<T>({ data: { items, pagination }, onPageSelect, children }: Props<T>) {
|
||||
const isFirstPage = pagination.currentPage === 1;
|
||||
|
||||
@@ -33,8 +33,8 @@ const NotFound = () => {
|
||||
<div className='flex flex-col gap-8 max-w-sm text-left'>
|
||||
<h1 className='text-[32px] font-extrabold leading-[98%] tracking-[-0.11rem]'>Page Not Found</h1>
|
||||
<p className=''>
|
||||
We couldn't find the page you're looking for. You may have lost access, or the page may have
|
||||
been removed. Here are some helpful links instead:
|
||||
We couldn't find the page you're looking for. You may have lost access, or the page
|
||||
may have been removed. Here are some helpful links instead:
|
||||
</p>
|
||||
<div className='flex flex-col gap-2'>
|
||||
<Link to={'/'} className='text-brand'>
|
||||
|
||||
@@ -31,12 +31,12 @@ const SpinnerComponent = styled.div<Props>`
|
||||
props.size === 'small'
|
||||
? `width: 16px; height: 16px; border-width: 2px;`
|
||||
: props.size === 'large'
|
||||
? css`
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-width: 6px;
|
||||
`
|
||||
: null};
|
||||
? css`
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-width: 6px;
|
||||
`
|
||||
: null};
|
||||
|
||||
border-color: ${(props) => (!props.isBlue ? 'rgba(255, 255, 255, 0.2)' : 'hsla(212, 92%, 43%, 0.2)')};
|
||||
border-top-color: ${(props) => (!props.isBlue ? 'rgb(255, 255, 255)' : 'hsl(212, 92%, 43%)')};
|
||||
@@ -58,6 +58,7 @@ Spinner.Size = {
|
||||
LARGE: 'large',
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
Spinner.Suspense = ({ children, centered = true, size = Spinner.Size.LARGE, ...props }) => (
|
||||
// <Spinner centered={centered} size={size} {...props} />
|
||||
<Suspense fallback={null} {...props}>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { v4 } from 'uuid';
|
||||
import Label from '@/components/elements/Label';
|
||||
import Input from '@/components/elements/Input';
|
||||
|
||||
const ToggleContainer = styled.div``
|
||||
const ToggleContainer = styled.div``;
|
||||
|
||||
// const ToggleContainer = styled.div`
|
||||
// ${tw`relative select-none w-12 leading-normal`};
|
||||
@@ -67,11 +67,7 @@ const Switch = ({ name, label, description, defaultChecked, readOnly, onChange,
|
||||
</ToggleContainer>
|
||||
{(label || description) && (
|
||||
<div className={`ml-4 w-full`}>
|
||||
{label && (
|
||||
<Label htmlFor={uuid}>
|
||||
{label}
|
||||
</Label>
|
||||
)}
|
||||
{label && <Label htmlFor={uuid}>{label}</Label>}
|
||||
{description && <p className={`text-zinc-400 text-sm mt-2`}>{description}</p>}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -17,7 +17,7 @@ export default ({ type, className, children }: AlertProps) => {
|
||||
['border-red-500 bg-red-500/25']: type === 'danger',
|
||||
['border-yellow-500 bg-yellow-500/25']: type === 'warning',
|
||||
},
|
||||
className
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{type === 'danger' ? (
|
||||
|
||||
@@ -17,14 +17,14 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
[styles.small]: size === Options.Size.Small,
|
||||
[styles.large]: size === Options.Size.Large,
|
||||
},
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const TextButton = forwardRef<HTMLButtonElement, ButtonProps>(({ className, ...props }, ref) => (
|
||||
|
||||
@@ -20,7 +20,7 @@ export default ({ type, position, className }: DialogIconProps) => {
|
||||
<div className={clsx(styles.dialog_icon, styles[type], className)}>
|
||||
{/* <Icon className={'w-6 h-6'} /> */}
|
||||
<div>FIXME: Icons</div>
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
}, [type, className]);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ const Input = Object.assign(
|
||||
{
|
||||
Text: InputField,
|
||||
Checkbox: Checkbox,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export { Input };
|
||||
|
||||
@@ -16,8 +16,8 @@ function FadeTransition({ children, duration, ...props }: Props) {
|
||||
const [enterDuration, exitDuration] = Array.isArray(duration)
|
||||
? duration
|
||||
: !duration
|
||||
? ['duration-200', 'duration-100']
|
||||
: [duration, duration];
|
||||
? ['duration-200', 'duration-100']
|
||||
: [duration, duration];
|
||||
|
||||
return (
|
||||
<Transition
|
||||
|
||||
@@ -5,7 +5,7 @@ export default () => {
|
||||
const status = ServerContext.useStoreState((state) => state.server.data?.status || null);
|
||||
const isTransferring = ServerContext.useStoreState((state) => state.server.data?.isTransferring || false);
|
||||
const isNodeUnderMaintenance = ServerContext.useStoreState(
|
||||
(state) => state.server.data?.isNodeUnderMaintenance || false
|
||||
(state) => state.server.data?.isNodeUnderMaintenance || false,
|
||||
);
|
||||
|
||||
return status === 'installing' || status === 'install_failed' || status === 'reinstall_failed' ? (
|
||||
|
||||
@@ -55,7 +55,7 @@ function WebsocketHandler() {
|
||||
updateToken(uuid, socket);
|
||||
} else {
|
||||
setError(
|
||||
'There was an error validating the credentials provided for the websocket. Please refresh the page.'
|
||||
'There was an error validating the credentials provided for the websocket. Please refresh the page.',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -13,10 +13,9 @@ import Can from '@/components/elements/Can';
|
||||
|
||||
interface Props {
|
||||
backup: ServerBackup;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default ({ backup, className }: Props) => {
|
||||
export default ({ backup }: Props) => {
|
||||
const { mutate } = getServerBackups();
|
||||
|
||||
useWebsocketEvent(`${SocketEvent.BACKUP_COMPLETED}:${backup.uuid}` as SocketEvent, async (data) => {
|
||||
|
||||
@@ -82,7 +82,7 @@ export default () => {
|
||||
.then(async (backup) => {
|
||||
await mutate(
|
||||
(data) => ({ ...data!, items: data!.items.concat(backup), backupCount: data!.backupCount + 1 }),
|
||||
false
|
||||
false,
|
||||
);
|
||||
setVisible(false);
|
||||
})
|
||||
|
||||
@@ -21,7 +21,9 @@ type Stats = Record<'memory' | 'cpu' | 'disk' | 'uptime' | 'rx' | 'tx', number>;
|
||||
// return undefined;
|
||||
// };
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const Limit = ({ limit, children }: { limit: string | null; children: React.ReactNode }) => <>{children}</>;
|
||||
|
||||
const ServerDetailsBlock = ({ className }: { className?: string }) => {
|
||||
|
||||
@@ -22,7 +22,7 @@ const schema = object().shape({
|
||||
.max(48, 'Database name must not exceed 48 characters.')
|
||||
.matches(
|
||||
/^[\w\-.]{3,48}$/,
|
||||
'Database name should only contain alphanumeric characters, underscores, dashes, and/or periods.'
|
||||
'Database name should only contain alphanumeric characters, underscores, dashes, and/or periods.',
|
||||
),
|
||||
connectionsFrom: string().matches(/^[\w\-/.%:]+$/, 'A valid host address must be provided.'),
|
||||
});
|
||||
@@ -89,16 +89,10 @@ export default () => {
|
||||
/>
|
||||
</div>
|
||||
<div className={`flex flex-wrap justify-end mt-6`}>
|
||||
<Button
|
||||
type={'button'}
|
||||
isSecondary
|
||||
onClick={() => setVisible(false)}
|
||||
>
|
||||
<Button type={'button'} isSecondary onClick={() => setVisible(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type={'submit'}>
|
||||
Create Database
|
||||
</Button>
|
||||
<Button type={'submit'}>Create Database</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@@ -53,23 +53,23 @@ export default () => {
|
||||
// <Spinner size={'large'} centered />
|
||||
<></>
|
||||
) : (
|
||||
<>
|
||||
{databases.length > 0 ? (
|
||||
databases.map((database, index) => (
|
||||
<DatabaseRow
|
||||
key={database.id}
|
||||
database={database}
|
||||
className={index > 0 ? 'mt-1' : undefined}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<p className={`text-center text-sm text-zinc-300`}>
|
||||
{databaseLimit > 0
|
||||
? 'It looks like you have no databases.'
|
||||
: 'Databases cannot be created for this server.'}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
<>
|
||||
{databases.length > 0 ? (
|
||||
databases.map((database, index) => (
|
||||
<DatabaseRow
|
||||
key={database.id}
|
||||
database={database}
|
||||
className={index > 0 ? 'mt-1' : undefined}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<p className={`text-center text-sm text-zinc-300`}>
|
||||
{databaseLimit > 0
|
||||
? 'It looks like you have no databases.'
|
||||
: 'Databases cannot be created for this server.'}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</ServerContentBlock>
|
||||
);
|
||||
|
||||
@@ -91,9 +91,7 @@ const GSLTokenModalFeature = () => {
|
||||
/>
|
||||
</div>
|
||||
<div className={`mt-8 sm:flex items-center justify-end`}>
|
||||
<Button type={'submit'}>
|
||||
Update GSL Token
|
||||
</Button>
|
||||
<Button type={'submit'}>Update GSL Token</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@@ -100,7 +100,7 @@ const JavaVersionModalFeature = () => {
|
||||
</div>
|
||||
</Can>
|
||||
<div className={`mt-8 flex flex-col sm:flex-row justify-end sm:space-x-4 space-y-4 sm:space-y-0`}>
|
||||
<Button isSecondary onClick={() => setVisible(false)} >
|
||||
<Button isSecondary onClick={() => setVisible(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Can action={'startup.docker-image'}>
|
||||
|
||||
@@ -61,8 +61,8 @@ const PIDLimitModalFeature = () => {
|
||||
<p className={`mt-4`}>This server has reached the maximum process or memory limit.</p>
|
||||
<p className={`mt-4`}>
|
||||
Increasing <code className={`font-mono bg-zinc-900`}>container_pid_limit</code> in the wings
|
||||
configuration, <code className={`font-mono bg-zinc-900`}>config.yml</code>, might help resolve this
|
||||
issue.
|
||||
configuration, <code className={`font-mono bg-zinc-900`}>config.yml</code>, might help resolve
|
||||
this issue.
|
||||
</p>
|
||||
<p className={`mt-4`}>
|
||||
<b>Note: Wings must be restarted for the configuration file changes to take effect</b>
|
||||
|
||||
@@ -57,13 +57,11 @@ const SteamDiskSpaceFeature = () => {
|
||||
</p>
|
||||
<p className={`mt-4`}>
|
||||
Ensure the machine has enough disk space by typing{' '}
|
||||
<code className={`font-mono bg-zinc-900 rounded py-1 px-2`}>df -h</code> on the machine hosting this
|
||||
server. Delete files or increase the available disk space to resolve the issue.
|
||||
<code className={`font-mono bg-zinc-900 rounded py-1 px-2`}>df -h</code> on the machine hosting
|
||||
this server. Delete files or increase the available disk space to resolve the issue.
|
||||
</p>
|
||||
<div className={`mt-8 sm:flex items-center justify-end`}>
|
||||
<Button onClick={() => setVisible(false)}>
|
||||
Close
|
||||
</Button>
|
||||
<Button onClick={() => setVisible(false)}>Close</Button>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
@@ -76,9 +74,7 @@ const SteamDiskSpaceFeature = () => {
|
||||
process. Please get in touch with the administrator(s) and inform them of disk space issues.
|
||||
</p>
|
||||
<div className={`mt-8 sm:flex items-center justify-end`}>
|
||||
<Button onClick={() => setVisible(false)}>
|
||||
Close
|
||||
</Button>
|
||||
<Button onClick={() => setVisible(false)}>Close</Button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -81,9 +81,7 @@ const EulaModalFeature = () => {
|
||||
<Button isSecondary onClick={() => setVisible(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={onAcceptEULA}>
|
||||
I Accept
|
||||
</Button>
|
||||
<Button onClick={onAcceptEULA}>I Accept</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
@@ -33,9 +33,9 @@ const ChmodFileModal = ({ files, ...props }: OwnProps) => {
|
||||
await mutate(
|
||||
(data) =>
|
||||
data!.map((f) =>
|
||||
f.name === files[0]?.file ? { ...f, mode: fileBitsToString(mode, !f.isFile), modeBits: mode } : f
|
||||
f.name === files[0]?.file ? { ...f, mode: fileBitsToString(mode, !f.isFile), modeBits: mode } : f,
|
||||
),
|
||||
false
|
||||
false,
|
||||
);
|
||||
|
||||
const data = files.map((f) => ({ file: f.file, mode: mode }));
|
||||
|
||||
@@ -130,7 +130,7 @@ export default () => {
|
||||
/>
|
||||
</div> */}
|
||||
<div>
|
||||
Note: File editing is currently disabled while we migrate pyrodactyl's built-in editor to a newer
|
||||
Note: File editing is currently disabled while we migrate pyrodactyl's built-in editor to a newer
|
||||
version. This message is here to prevent errors on your end. Thanks for your patience!
|
||||
</div>
|
||||
{/* <div css={tw`flex justify-end mt-4`}>
|
||||
|
||||
@@ -100,7 +100,7 @@ export default () => {
|
||||
cy='12'
|
||||
r='10'
|
||||
stroke='currentColor'
|
||||
stroke-width='4'
|
||||
strokeWidth='4'
|
||||
></circle>
|
||||
<path
|
||||
className='opacity-75'
|
||||
|
||||
@@ -20,7 +20,7 @@ function isFileOrDirectory(event: DragEvent): boolean {
|
||||
|
||||
export default () => {
|
||||
const fileUploadInput = useRef<HTMLInputElement>(null);
|
||||
const [timeouts, setTimeouts] = useState<NodeJS.Timeout[]>([]);
|
||||
const [timeouts, _] = useState<NodeJS.Timeout[]>([]);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { mutate } = useFileManagerSwr();
|
||||
const { addError, clearAndAddHttpError } = useFlashKey('files');
|
||||
@@ -133,8 +133,8 @@ export default () => {
|
||||
fill='white'
|
||||
/>
|
||||
<path
|
||||
fill-rule='evenodd'
|
||||
clip-rule='evenodd'
|
||||
fillRule='evenodd'
|
||||
clipRule='evenodd'
|
||||
d='M9.59334 5.25H9.59333H9.59332H8.40669H8.40667H8.40666C6.93025 5.24998 5.74683 5.24997 4.81751 5.37372C3.85586 5.50178 3.05447 5.77447 2.41849 6.4044C1.78151 7.03531 1.50485 7.83196 1.3751 8.78785C1.24997 9.70973 1.24998 10.8831 1.25 12.3443V12.3443V12.3443V15.6557V15.6557V15.6557C1.24998 17.1169 1.24997 18.2903 1.3751 19.2122C1.50485 20.168 1.78151 20.9647 2.41849 21.5956C3.05447 22.2255 3.85586 22.4982 4.81751 22.6263C5.74682 22.75 6.93025 22.75 8.40666 22.75H9.59335C11.0698 22.75 12.2532 22.75 13.1825 22.6263C14.1441 22.4982 14.9455 22.2255 15.5815 21.5956C16.2185 20.9647 16.4952 20.168 16.6249 19.2122C16.75 18.2903 16.75 17.1169 16.75 15.6557V12.3443C16.75 10.8831 16.75 9.70973 16.6249 8.78785C16.4952 7.83196 16.2185 7.03531 15.5815 6.4044C14.9455 5.77447 14.1441 5.50178 13.1825 5.37372C12.2532 5.24997 11.0698 5.24998 9.59334 5.25ZM6 11C5.44772 11 5 11.4477 5 12C5 12.5523 5.44772 13 6 13H9C9.55229 13 10 12.5523 10 12C10 11.4477 9.55229 11 9 11H6ZM6 16C5.44772 16 5 16.4477 5 17C5 17.5523 5.44772 18 6 18H11C11.5523 18 12 17.5523 12 17C12 16.4477 11.5523 16 11 16H6Z'
|
||||
fill='white'
|
||||
/>
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import getServerSchedules from '@/api/server/schedules/getServerSchedules';
|
||||
import { ServerContext } from '@/state/server';
|
||||
import Spinner from '@/components/elements/Spinner';
|
||||
import FlashMessageRender from '@/components/FlashMessageRender';
|
||||
import ScheduleRow from '@/components/server/schedules/ScheduleRow';
|
||||
import { httpErrorToHuman } from '@/api/http';
|
||||
import EditScheduleModal from '@/components/server/schedules/EditScheduleModal';
|
||||
import Can from '@/components/elements/Can';
|
||||
import useFlash from '@/plugins/useFlash';
|
||||
import GreyRowBox from '@/components/elements/GreyRowBox';
|
||||
import { Button } from '@/components/elements/button/index';
|
||||
import ServerContentBlock from '@/components/elements/ServerContentBlock';
|
||||
import { Link, NavLink } from 'react-router-dom';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
function ScheduleContainer() {
|
||||
const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid);
|
||||
|
||||
@@ -26,10 +26,10 @@ const CronBox = ({ title, value }: { title: string; value: string }) => (
|
||||
|
||||
const ActivePill = ({ active }: { active: boolean }) => (
|
||||
<span
|
||||
// css={[
|
||||
// tw`rounded-full px-2 py-px text-xs ml-4 uppercase`,
|
||||
// active ? tw`bg-green-600 text-green-100` : tw`bg-red-600 text-red-100`,
|
||||
// ]}
|
||||
// css={[
|
||||
// tw`rounded-full px-2 py-px text-xs ml-4 uppercase`,
|
||||
// active ? tw`bg-green-600 text-green-100` : tw`bg-red-600 text-red-100`,
|
||||
// ]}
|
||||
>
|
||||
{active ? 'Active' : 'Inactive'}
|
||||
</span>
|
||||
@@ -48,7 +48,7 @@ export default () => {
|
||||
|
||||
const schedule = ServerContext.useStoreState(
|
||||
(st) => st.schedules.data.find((s) => s.id === Number(scheduleId)),
|
||||
isEqual
|
||||
isEqual,
|
||||
);
|
||||
const appendSchedule = ServerContext.useStoreActions((actions) => actions.schedules.appendSchedule);
|
||||
|
||||
@@ -134,7 +134,7 @@ export default () => {
|
||||
{schedule.tasks.length > 0
|
||||
? schedule.tasks
|
||||
.sort((a, b) =>
|
||||
a.sequenceId === b.sequenceId ? 0 : a.sequenceId > b.sequenceId ? 1 : -1
|
||||
a.sequenceId === b.sequenceId ? 0 : a.sequenceId > b.sequenceId ? 1 : -1,
|
||||
)
|
||||
.map((task) => (
|
||||
<ScheduleTaskRow
|
||||
|
||||
@@ -43,7 +43,7 @@ export default ({ schedule, task }: Props) => {
|
||||
appendSchedule({
|
||||
...schedule,
|
||||
tasks: schedule.tasks.filter((t) => t.id !== task.id),
|
||||
})
|
||||
}),
|
||||
)
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
@@ -91,7 +91,9 @@ export default ({ schedule, task }: Props) => {
|
||||
<div className={`mt-3 sm:mt-0 flex items-center w-full sm:w-auto`}>
|
||||
{task.continueOnFailure && (
|
||||
<div className={`mr-6`}>
|
||||
<div className={`flex items-center px-2 py-1 bg-yellow-500 text-yellow-800 text-sm rounded-full`}>
|
||||
<div
|
||||
className={`flex items-center px-2 py-1 bg-yellow-500 text-yellow-800 text-sm rounded-full`}
|
||||
>
|
||||
Continues on Failure
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ServerContext } from '@/state/server';
|
||||
import TitledGreyBox from '@/components/elements/TitledGreyBox';
|
||||
import { Form, Formik, FormikHelpers } from 'formik';
|
||||
import { Form, Formik } from 'formik';
|
||||
import { toast } from 'sonner';
|
||||
import { Actions, useStoreActions } from 'easy-peasy';
|
||||
import renameServer from '@/api/server/renameServer';
|
||||
|
||||
@@ -24,7 +24,7 @@ export default () => {
|
||||
<div className={'flex flex-row justify-between items-center mb-8'}>
|
||||
<h1 className='text-[52px] font-extrabold leading-[98%] tracking-[-0.14rem]'>Settings</h1>
|
||||
</div>
|
||||
<FlashMessageRender byKey={'settings'} className={`mb-4`} />
|
||||
<FlashMessageRender byKey={'settings'} />
|
||||
<Can action={'settings.rename'}>
|
||||
<div className={`mb-6 md:mb-10`}>
|
||||
<RenameServerBox />
|
||||
|
||||
@@ -13,14 +13,14 @@ import isEqual from 'react-fast-compare';
|
||||
import Input from '@/components/elements/Input';
|
||||
import setSelectedDockerImage from '@/api/server/setSelectedDockerImage';
|
||||
import InputSpinner from '@/components/elements/InputSpinner';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/elements/DropdownMenu';
|
||||
// import {
|
||||
// DropdownMenu,
|
||||
// DropdownMenuContent,
|
||||
// DropdownMenuItem,
|
||||
// DropdownMenuRadioGroup,
|
||||
// DropdownMenuRadioItem,
|
||||
// DropdownMenuTrigger,
|
||||
// } from '@/components/elements/DropdownMenu';
|
||||
import useFlash from '@/plugins/useFlash';
|
||||
import CopyOnClick from '@/components/elements/CopyOnClick';
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import { ServerEggVariable } from '@/api/server/types';
|
||||
import TitledGreyBox from '@/components/elements/TitledGreyBox';
|
||||
import { usePermissions } from '@/plugins/usePermissions';
|
||||
import InputSpinner from '@/components/elements/InputSpinner';
|
||||
import Input from '@/components/elements/Input';
|
||||
import Switch from '@/components/elements/Switch';
|
||||
import debounce from 'debounce';
|
||||
import updateStartupVariable from '@/api/server/updateStartupVariable';
|
||||
@@ -59,7 +58,7 @@ const VariableBox = ({ variable }: Props) => {
|
||||
|
||||
return (
|
||||
<TitledGreyBox>
|
||||
<FlashMessageRender byKey={FLASH_KEY} className={`mb-2 md:mb-4`} />
|
||||
<FlashMessageRender byKey={FLASH_KEY} />
|
||||
<div className={`text-sm mb-2`}>
|
||||
{!variable.isEditable && (
|
||||
<span className={`bg-neutral-700 text-xs py-1 px-2 rounded-full mr-2 mb-1`}>Read Only</span>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import EditSubuserModal from '@/components/server/users/EditSubuserModal';
|
||||
import { Button } from '@/components/elements/button/index';
|
||||
|
||||
export default () => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
@@ -31,7 +31,7 @@ const EditSubuserModal = ({ subuser }: Props) => {
|
||||
const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid);
|
||||
const appendSubuser = ServerContext.useStoreActions((actions) => actions.subusers.appendSubuser);
|
||||
const { clearFlashes, clearAndAddHttpError } = useStoreActions(
|
||||
(actions: Actions<ApplicationStore>) => actions.flashes
|
||||
(actions: Actions<ApplicationStore>) => actions.flashes,
|
||||
);
|
||||
const { dismiss, setPropOverrides } = useContext(ModalContext);
|
||||
|
||||
@@ -45,7 +45,7 @@ const EditSubuserModal = ({ subuser }: Props) => {
|
||||
// The permissions that can be modified by this user.
|
||||
const editablePermissions = useDeepCompareMemo(() => {
|
||||
const cleaned = Object.keys(permissions).map((key) =>
|
||||
Object.keys(permissions[key]?.keys ?? {}).map((pkey) => `${key}.${pkey}`)
|
||||
Object.keys(permissions[key]?.keys ?? {}).map((pkey) => `${key}.${pkey}`),
|
||||
);
|
||||
|
||||
const list: string[] = ([] as string[]).concat.apply([], Object.values(cleaned));
|
||||
@@ -81,7 +81,7 @@ const EditSubuserModal = ({ subuser }: Props) => {
|
||||
() => () => {
|
||||
clearFlashes('user:edit');
|
||||
},
|
||||
[]
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -114,7 +114,7 @@ const EditSubuserModal = ({ subuser }: Props) => {
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<FlashMessageRender byKey={'user:edit'} className={`mt-4`} />
|
||||
<FlashMessageRender byKey={'user:edit'} />
|
||||
{!isRootAdmin && loggedInPermissions[0] !== '*' && (
|
||||
<div className={`mt-4 pl-4 py-2 border-l-4 border-blue-400`}>
|
||||
<p className={`text-sm text-zinc-300`}>
|
||||
|
||||
@@ -22,7 +22,7 @@ const PermissionTitleBox: React.FC<Props> = memo(({ isEditable, title, permissio
|
||||
setValue(value.filter((p) => !permissions.includes(p)));
|
||||
}
|
||||
},
|
||||
[permissions, value]
|
||||
[permissions, value],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useEffect, useState } from 'react';
|
||||
import { ServerContext } from '@/state/server';
|
||||
import { Actions, useStoreActions, useStoreState } from 'easy-peasy';
|
||||
import { ApplicationStore } from '@/state';
|
||||
import Spinner from '@/components/elements/Spinner';
|
||||
import AddSubuserButton from '@/components/server/users/AddSubuserButton';
|
||||
import UserRow from '@/components/server/users/UserRow';
|
||||
import FlashMessageRender from '@/components/FlashMessageRender';
|
||||
@@ -49,7 +48,7 @@ export default () => {
|
||||
|
||||
return (
|
||||
<ServerContentBlock title={'Users'}>
|
||||
<FlashMessageRender byKey={'users'} className={`mb-4`} />
|
||||
<FlashMessageRender byKey={'users'} />
|
||||
<div className={'flex flex-row justify-between items-center mb-8'}>
|
||||
<h1 className='text-[52px] font-extrabold leading-[98%] tracking-[-0.14rem]'>Users</h1>
|
||||
<Can action={'user.create'}>
|
||||
|
||||
@@ -7,7 +7,7 @@ export interface ModalContextValues {
|
||||
value:
|
||||
| ((current: Readonly<Partial<SettableModalProps>>) => Partial<SettableModalProps>)
|
||||
| Partial<SettableModalProps>
|
||||
| null
|
||||
| null,
|
||||
) => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState } from 'react';
|
||||
import { Dialog, DialogProps, DialogWrapperContext, WrapperProps } from '@/components/elements/dialog';
|
||||
|
||||
function asDialog(
|
||||
initialProps?: WrapperProps
|
||||
initialProps?: WrapperProps,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
): <P extends {}>(C: React.ComponentType<P>) => React.FunctionComponent<P & DialogProps> {
|
||||
return function (Component) {
|
||||
|
||||
@@ -19,7 +19,7 @@ interface State {
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
function asModal<P extends {}>(
|
||||
modalProps?: SettableModalProps | ((props: P) => SettableModalProps)
|
||||
modalProps?: SettableModalProps | ((props: P) => SettableModalProps),
|
||||
): (Component: any) => any {
|
||||
return function (Component) {
|
||||
return class extends PureComponent<P & AsModalProps, State> {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// I know it's deprecated! We need to fix it!!!
|
||||
// eslint-disable-next-line react/no-deprecated
|
||||
import { render } from 'react-dom';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import App from '@/components/App';
|
||||
|
||||
@@ -16,7 +16,7 @@ describe('@/lib/objects.ts', function () {
|
||||
'should return false for %p',
|
||||
function (value) {
|
||||
expect(isObject(value)).toBe(false);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { type ClassValue, clsx } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
4
resources/scripts/macros.d.ts
vendored
4
resources/scripts/macros.d.ts
vendored
@@ -15,10 +15,10 @@ declare module 'styled-components' {
|
||||
T extends object,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
O extends object = {},
|
||||
A extends keyof any = never
|
||||
A extends keyof any = never,
|
||||
> extends ForwardRefExoticBase<StyledComponentProps<C, T, O, A>> {
|
||||
(
|
||||
props: StyledComponentProps<C, T, O, A> & { as?: Element | string; forwardedAs?: never | undefined }
|
||||
props: StyledComponentProps<C, T, O, A> & { as?: Element | string; forwardedAs?: never | undefined },
|
||||
): ReactElement<StyledComponentProps<C, T, O, A>>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ export class Websocket extends EventEmitter {
|
||||
JSON.stringify({
|
||||
event,
|
||||
args: Array.isArray(payload) ? payload : [payload],
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useEffect, useRef } from 'react';
|
||||
export default (
|
||||
eventName: string,
|
||||
handler: (e: Event | CustomEvent | UIEvent | any) => void,
|
||||
options?: boolean | EventListenerOptions
|
||||
options?: boolean | EventListenerOptions,
|
||||
) => {
|
||||
const savedHandler = useRef<any>(null);
|
||||
|
||||
|
||||
@@ -17,6 +17,6 @@ export default () => {
|
||||
revalidateOnMount: false,
|
||||
refreshInterval: 0,
|
||||
errorRetryCount: 2,
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ export const usePermissions = (action: string | string[]): boolean[] => {
|
||||
(permission.endsWith('.*') &&
|
||||
userPermissions.filter((p) => p.startsWith(permission.split('.')?.[0] ?? '')).length > 0) ||
|
||||
// Otherwise just check if the entire permission exists in the array or not.
|
||||
userPermissions.indexOf(permission) >= 0
|
||||
userPermissions.indexOf(permission) >= 0,
|
||||
);
|
||||
}, [action, userPermissions]);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
||||
|
||||
export function usePersistedState<S = undefined>(
|
||||
key: string,
|
||||
defaultValue: S
|
||||
defaultValue: S,
|
||||
): [S | undefined, Dispatch<SetStateAction<S | undefined>>] {
|
||||
const [state, setState] = useState(() => {
|
||||
try {
|
||||
|
||||
@@ -43,6 +43,7 @@ export default defineConfig({
|
||||
manualChunks(id) {
|
||||
if (id.includes('node_modules')) {
|
||||
// @ts-expect-error
|
||||
// It won't fail lol
|
||||
return id.toString().split('node_modules/')[1].split('/')[0].toString();
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user