feat: make linting functional + lint pass

This commit is contained in:
fero
2024-03-24 19:05:44 -07:00
parent e15457fda5
commit b129d398e4
93 changed files with 245 additions and 229 deletions

View File

@@ -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
View File

@@ -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",

View File

@@ -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",

View File

@@ -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 || {}) },
);
};

View File

@@ -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);
});

View File

@@ -18,7 +18,7 @@ const useSSHKeys = (config?: SWRConfiguration<SSHKey[], AxiosError>) => {
return Transformers.toSSHKey(datum.attributes);
});
},
{ revalidateOnMount: false, ...(config || {}) }
{ revalidateOnMount: false, ...(config || {}) },
);
};

View File

@@ -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)) {

View File

@@ -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);
});

View File

@@ -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);
});

View File

@@ -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>[],

View File

@@ -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);
});

View File

@@ -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];

View File

@@ -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;
},
);
};
};

View File

@@ -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 || {}) },
);
};

View File

@@ -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);

View File

@@ -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);
});

View File

@@ -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);

View File

@@ -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.',
}
},
);
};

View File

@@ -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);
});

View File

@@ -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);
});

View File

@@ -12,7 +12,7 @@ export default (server: string): Promise<Response> => {
resolve({
token: data.data.token,
socket: data.data.socket,
})
}),
)
.catch(reject);
});

View File

@@ -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);

View File

@@ -15,6 +15,6 @@ export default () => {
return (data.data || []).map(rawDataToServerAllocation);
},
{ revalidateOnFocus: false, revalidateOnMount: false }
{ revalidateOnFocus: false, revalidateOnMount: false },
);
};
};

View File

@@ -29,4 +29,4 @@ export default () => {
backupCount: data.meta.backup_count,
};
});
};
};

View File

@@ -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 ?? {}) },
);

View File

@@ -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 ? (

View File

@@ -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&apos;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

View File

@@ -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={

View File

@@ -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`}

View File

@@ -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>
) : (

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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 />

View File

@@ -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();

View File

@@ -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));
};

View File

@@ -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>

View File

@@ -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';

View File

@@ -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} />}

View File

@@ -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}
>

View File

@@ -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}
>

View File

@@ -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';

View File

@@ -1,7 +1,5 @@
const Icon = () => {
return (
<div>This component is deprecated.</div>
);
return <div>This component is deprecated.</div>;
};
export default Icon;

View File

@@ -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'] {
}
}
`;

View File

@@ -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';

View File

@@ -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;

View File

@@ -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&apos;t find the page you&apos;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'>

View File

@@ -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}>

View File

@@ -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>
)}

View File

@@ -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' ? (

View File

@@ -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) => (

View File

@@ -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]);

View File

@@ -6,7 +6,7 @@ const Input = Object.assign(
{
Text: InputField,
Checkbox: Checkbox,
}
},
);
export { Input };

View File

@@ -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

View File

@@ -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' ? (

View File

@@ -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.',
);
}
});

View File

@@ -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) => {

View File

@@ -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);
})

View File

@@ -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 }) => {

View File

@@ -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>

View File

@@ -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>
);

View File

@@ -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>

View File

@@ -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'}>

View File

@@ -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>

View File

@@ -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>
</>
)}

View File

@@ -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>
);

View File

@@ -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 }));

View File

@@ -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&apos;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`}>

View File

@@ -100,7 +100,7 @@ export default () => {
cy='12'
r='10'
stroke='currentColor'
stroke-width='4'
strokeWidth='4'
></circle>
<path
className='opacity-75'

View File

@@ -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'
/>

View File

@@ -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);

View File

@@ -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

View File

@@ -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>

View File

@@ -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';

View File

@@ -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 />

View File

@@ -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';

View File

@@ -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>

View File

@@ -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);

View File

@@ -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`}>

View File

@@ -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 (

View File

@@ -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'}>

View File

@@ -7,7 +7,7 @@ export interface ModalContextValues {
value:
| ((current: Readonly<Partial<SettableModalProps>>) => Partial<SettableModalProps>)
| Partial<SettableModalProps>
| null
| null,
) => void;
}

View File

@@ -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) {

View File

@@ -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> {

View File

@@ -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';

View File

@@ -16,7 +16,7 @@ describe('@/lib/objects.ts', function () {
'should return false for %p',
function (value) {
expect(isObject(value)).toBe(false);
}
},
);
});
});

View File

@@ -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));
}

View File

@@ -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>>;
}
}

View File

@@ -100,7 +100,7 @@ export class Websocket extends EventEmitter {
JSON.stringify({
event,
args: Array.isArray(payload) ? payload : [payload],
})
}),
);
}
}

View File

@@ -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);

View File

@@ -17,6 +17,6 @@ export default () => {
revalidateOnMount: false,
refreshInterval: 0,
errorRetryCount: 2,
}
},
);
};

View File

@@ -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]);
};

View File

@@ -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 {

View File

@@ -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();
}
},