Linter rules update

This commit is contained in:
Erik 2024-05-01 16:57:32 +03:00
parent e68de7f432
commit 29da1ceace
23 changed files with 148 additions and 126 deletions

View File

@ -15,7 +15,8 @@
"jsx": true "jsx": true
}, },
"ecmaVersion": 12, "ecmaVersion": 12,
"sourceType": "module" "sourceType": "module",
"project": "./tsconfig.json"
}, },
"plugins": [ "plugins": [
"react", "react",
@ -31,11 +32,18 @@
"allman" "allman"
], ],
"indent": ["warn", 4, { "indent": ["warn", 4, {
"SwitchCase": 1 "SwitchCase": 1,
"VariableDeclarator": "first",
"FunctionDeclaration": {"parameters": "first"},
"CallExpression": {"arguments": "first"},
"ArrayExpression": "first",
"ObjectExpression": "first",
"ImportDeclaration": "first"
}], }],
"no-warning-comments": [1, { "no-warning-comments": [1, {
"terms": ["todo", "fixme"] "terms": ["todo", "fixme"]
}], }],
"no-multi-spaces": ["warn", {"ignoreEOLComments": true, "exceptions": {"ImportDeclaration": true}}],
"prefer-arrow-callback": "warn", "prefer-arrow-callback": "warn",
"prefer-const": "warn", "prefer-const": "warn",
"prefer-destructuring": "warn", "prefer-destructuring": "warn",
@ -77,7 +85,20 @@
"no-console": "warn", "no-console": "warn",
"no-constant-binary-expression": "error", "no-constant-binary-expression": "error",
"no-trailing-spaces": "warn", "no-trailing-spaces": "warn",
"no-tabs": "error",
"quotes": ["error" , "single"], "quotes": ["error" , "single"],
"jsx-quotes": [
"error",
"prefer-single"
],
"key-spacing": [
"warn",
{
"beforeColon": false,
"afterColon": true,
"align": "value"
}
],
"guard-for-in": "warn", "guard-for-in": "warn",
"yoda": [ "yoda": [
"warn", "warn",

View File

@ -77,13 +77,13 @@ const App = () =>
const menuItems: SidebarMenuItem[] = [ const menuItems: SidebarMenuItem[] = [
{ {
to: '/home', label: 'Home', items: [ to: '/home', label: 'Home', items: [
{ to: '/profile', label: 'Profile', relative: true }, { to: '/profile', label: 'Profile', relative: true },
{ to: '/applications', label: 'Applications', relative: true, permission: [ 'applications:*', 1 ] } { to: '/applications', label: 'Applications', relative: true, permission: [ 'applications:*', 1 ] }
] ]
}, },
{ {
to: '/admin', label: 'Admin', permission: [ 'administrator:*', 1 ], items: [ to: '/admin', label: 'Admin', permission: [ 'administrator:*', 1 ], items: [
{ to: '/users', label: 'Users', relative: true, permission: [ 'administrator:users:*', 1 ] }, { to: '/users', label: 'Users', relative: true, permission: [ 'administrator:users:*', 1 ] },
{ to: '/roles', label: 'Roles', relative: true, permission: [ 'administrator:roles:*', 1 ] }, { to: '/roles', label: 'Roles', relative: true, permission: [ 'administrator:roles:*', 1 ] },
{ to: '/flags', label: 'Flags', relative: true, permission: [ 'administrator:flags:*', 1 ] }, { to: '/flags', label: 'Flags', relative: true, permission: [ 'administrator:flags:*', 1 ] },
@ -101,7 +101,7 @@ const App = () =>
{user ? {user ?
<div> <div>
<header className=""> <header className=''>
{/* <OnlineList /> */} {/* <OnlineList /> */}
<UserControls /> <UserControls />
</header> </header>
@ -153,7 +153,7 @@ const App = () =>
</ErrorBoundary> </ErrorBoundary>
<div className={`footer ${user ? '' : 'login'}`}> <div className={`footer ${user ? '' : 'login'}`}>
<p className='m-0 text-center'>Made with <i className="icon corgi transparent"></i> by <a href="https://corgi.wtf" target="_blank" rel="noreferrer">Navy.gif</a> &nbsp;|&nbsp; Front-end magic by <a href="https://d3vision.dev" target="_blank" rel="noreferrer">D3vision</a></p> <p className='m-0 text-center'>Made with <i className='icon corgi transparent'></i> by <a href='https://corgi.wtf' target='_blank' rel='noreferrer'>Navy.gif</a> &nbsp;|&nbsp; Front-end magic by <a href='https://d3vision.dev' target='_blank' rel='noreferrer'>D3vision</a></p>
</div> </div>
</div> </div>

View File

@ -25,11 +25,11 @@ export const FileSelector = ({ file, cb, types = '' }: { types?: string, file: F
cb(file); cb(file);
}; };
return <label onDrop={onDrop} onDragOver={onDragOver} htmlFor="fileUpload" className="drop-container"> return <label onDrop={onDrop} onDragOver={onDragOver} htmlFor='fileUpload' className='drop-container'>
<span className="drop-title">Drag &apos;n&apos; drop a file here</span> <span className='drop-title'>Drag &apos;n&apos; drop a file here</span>
or or
<span className="drop-title">Click to select a file</span> <span className='drop-title'>Click to select a file</span>
<p className="fileName m-0">{file ? `Selected: ${file.name}` : null}</p> <p className='fileName m-0'>{file ? `Selected: ${file.name}` : null}</p>
<input onChange={(event) => <input onChange={(event) =>
{ {
if (!event.target.files) if (!event.target.files)
@ -37,7 +37,7 @@ export const FileSelector = ({ file, cb, types = '' }: { types?: string, file: F
const [ f ] = event.target.files; const [ f ] = event.target.files;
cb(f); cb(f);
}} }}
type="file" id="fileUpload" accept={types} required /> type='file' id='fileUpload' accept={types} required />
</label>; </label>;
}; };
@ -55,7 +55,7 @@ export type InputElementProperties<T> = {
export const ToggleSwitch = ({ name, defaultValue: value, onChange, inputRef, children, className = '' }: InputElementProperties<boolean>) => export const ToggleSwitch = ({ name, defaultValue: value, onChange, inputRef, children, className = '' }: InputElementProperties<boolean>) =>
{ {
return <label className={`label-fix ${className}`}> return <label className={`label-fix ${className}`}>
<span className="check-box check-box-row"> <span className='check-box check-box-row'>
{children && <b>{children}</b>} {children && <b>{children}</b>}
<input name={name} ref={inputRef} defaultChecked={value} onChange={onChange} type='checkbox' /> <input name={name} ref={inputRef} defaultChecked={value} onChange={onChange} type='checkbox' />
</span> </span>
@ -64,9 +64,9 @@ export const ToggleSwitch = ({ name, defaultValue: value, onChange, inputRef, ch
export const VerticalToggleSwitch = ({ name, defaultValue: value, onChange, inputRef, children }: InputElementProperties<boolean>) => export const VerticalToggleSwitch = ({ name, defaultValue: value, onChange, inputRef, children }: InputElementProperties<boolean>) =>
{ {
return <label className="label-fix"> return <label className='label-fix'>
{children && <b>{children}</b>} {children && <b>{children}</b>}
<span className="check-box"> <span className='check-box'>
<input name={name} ref={inputRef} defaultChecked={value} onChange={onChange} type='checkbox' /> <input name={name} ref={inputRef} defaultChecked={value} onChange={onChange} type='checkbox' />
</span> </span>
</label>; </label>;
@ -121,7 +121,7 @@ export const NumberInput = ({ name, children, placeholder, inputRef, onChange, d
ref={inputRef} ref={inputRef}
defaultValue={value} defaultValue={value}
onChange={onChange} onChange={onChange}
type="number" type='number'
min={min} min={min}
max={max} max={max}
step={step} step={step}
@ -164,7 +164,7 @@ export const ClickToEdit = ({ value, onUpdate, inputElement, placeholder }:
return <span className='input-group'> return <span className='input-group'>
{input} {input}
<div className='input-group-btn'> <div className='input-group-btn'>
<button className="button primary" onClick={onClick} >OK</button> <button className='button primary' onClick={onClick} >OK</button>
</div> </div>
</span>; </span>;
return <span onClick={() => setEditing(true)} className='mt-0 mb-1 clickable'>{value || placeholder}</span>; return <span onClick={() => setEditing(true)} className='mt-0 mb-1 clickable'>{value || placeholder}</span>;
@ -240,9 +240,9 @@ const DropdownComp = ({ children, className = '', onToggle }: DropdownProps) =>
}; };
const Dropdown = Object.assign(DropdownComp, { const Dropdown = Object.assign(DropdownComp, {
Header: DropdownHeader, Header: DropdownHeader,
ItemList: DropdownItemList, ItemList: DropdownItemList,
Item: DropdownItem Item: DropdownItem
}); });
export type InputElementType = export type InputElementType =

View File

@ -53,7 +53,7 @@ export const PageButtons = ({ setPage, page, pages, disabled }: PageButtonProps)
}; };
return <div className='flex is-vertical-align is-center page-controls'> return <div className='flex is-vertical-align is-center page-controls'>
<button className="button dark" disabled={page === 1 || disabled} onClick={previous}>Previous</button> <button className='button dark' disabled={page === 1 || disabled} onClick={previous}>Previous</button>
<div className='flex gap-3 align-items-center'><span>Page:</span> {showInput ? <input onKeyUp={(e) => <div className='flex gap-3 align-items-center'><span>Page:</span> {showInput ? <input onKeyUp={(e) =>
{ {
if (e.key === 'Enter') if (e.key === 'Enter')
@ -62,7 +62,7 @@ export const PageButtons = ({ setPage, page, pages, disabled }: PageButtonProps)
onEnter(field.value); onEnter(field.value);
} }
}} className='page-number-input mb-0 p-2 pb-1' defaultValue={page} type='number' /> : <span className='clickable' onClick={onClick}>{page}</span>}<span> / {pages || 1}</span></div> }} className='page-number-input mb-0 p-2 pb-1' defaultValue={page} type='number' /> : <span className='clickable' onClick={onClick}>{page}</span>}<span> / {pages || 1}</span></div>
<button className="button dark" disabled={page >= pages || disabled} onClick={next}>Next</button> <button className='button dark' disabled={page >= pages || disabled} onClick={next}>Next</button>
</div>; </div>;
}; };

View File

@ -29,18 +29,18 @@ export const Refresher = ({ state, className = '', tooltipText, onRefresh: onCli
onClick(); onClick();
}; };
return <div className={`refresher-wrapper ${className}`} {...tooltipText ? { 'data-tooltip': tooltipText } : {}}> return <div className={`refresher-wrapper ${className}`} {...tooltipText ? { 'data-tooltip': tooltipText } : {}}>
<div id="reportRefresher" className={`refresher ${stateClass}`} onClick={refresh}> <div id='reportRefresher' className={`refresher ${stateClass}`} onClick={refresh}>
<svg className="icon-loading" viewBox="0 0 32 32"> <svg className='icon-loading' viewBox='0 0 32 32'>
<path d="M 16 4 C 10.886719 4 6.617188 7.160156 4.875 11.625 L 6.71875 12.375 C 8.175781 8.640625 11.710938 6 16 6 C 19.242188 6 22.132813 7.589844 23.9375 10 L 20 10 L 20 12 L 27 12 L 27 5 L 25 5 L 25 8.09375 C 22.808594 5.582031 19.570313 4 16 4 Z M 25.28125 19.625 C 23.824219 23.359375 20.289063 26 16 26 C 12.722656 26 9.84375 24.386719 8.03125 22 L 12 22 L 12 20 L 5 20 L 5 27 L 7 27 L 7 23.90625 C 9.1875 26.386719 12.394531 28 16 28 C 21.113281 28 25.382813 24.839844 27.125 20.375 Z "> <path d='M 16 4 C 10.886719 4 6.617188 7.160156 4.875 11.625 L 6.71875 12.375 C 8.175781 8.640625 11.710938 6 16 6 C 19.242188 6 22.132813 7.589844 23.9375 10 L 20 10 L 20 12 L 27 12 L 27 5 L 25 5 L 25 8.09375 C 22.808594 5.582031 19.570313 4 16 4 Z M 25.28125 19.625 C 23.824219 23.359375 20.289063 26 16 26 C 12.722656 26 9.84375 24.386719 8.03125 22 L 12 22 L 12 20 L 5 20 L 5 27 L 7 27 L 7 23.90625 C 9.1875 26.386719 12.394531 28 16 28 C 21.113281 28 25.382813 24.839844 27.125 20.375 Z '>
</path> </path>
</svg> </svg>
<svg className="icon-success" viewBox="0 0 76 76"> <svg className='icon-success' viewBox='0 0 76 76'>
<path fill="none" strokeWidth="7" d="M17.5,40.9l10.9,10.9l28.7-28"></path> <path fill='none' strokeWidth='7' d='M17.5,40.9l10.9,10.9l28.7-28'></path>
</svg> </svg>
<svg className="icon-error" viewBox="0 0 20 20"> <svg className='icon-error' viewBox='0 0 20 20'>
<circle cx="10" cy="10" r="10"></circle> <circle cx='10' cy='10' r='10'></circle>
<polyline points="5 15, 15 5"></polyline> <polyline points='5 15, 15 5'></polyline>
<polyline points="15 15, 5 5"></polyline> <polyline points='15 15, 5 5'></polyline>
</svg> </svg>
</div> </div>
</div>; </div>;
@ -194,8 +194,8 @@ type BasePaginatedCardProps = {
// onlineList?: string // onlineList?: string
} }
export const BasePaginatedCard = ({ children, data, export const BasePaginatedCard = ({ children, data,
className, id, tableDivClass, formatter, callback, className, id, tableDivClass, formatter, callback,
page, pages, setPage, loadState, onRefresh }: BasePaginatedCardProps) => page, pages, setPage, loadState, onRefresh }: BasePaginatedCardProps) =>
{ {
if (!(children instanceof Array)) if (!(children instanceof Array))
children = [ children ]; children = [ children ];

View File

@ -12,7 +12,7 @@ const Sidebar = ({ children }: {children?: React.ReactNode}) =>
{ {
return <div className='sidebar card'> return <div className='sidebar card'>
<div className='flex align-items-center'> <div className='flex align-items-center'>
<img className="sidebar-logo" src={logoImg}/> <img className='sidebar-logo' src={logoImg}/>
<span className='hamburger mr-5 mb-2' onClick={expandMobileMenu}></span> <span className='hamburger mr-5 mb-2' onClick={expandMobileMenu}></span>
</div> </div>
{children} {children}
@ -83,7 +83,7 @@ const SidebarMenu = ({ menuItems = [], children }: {menuItems: SidebarMenuItem[]
}); });
let link = <NavLink className={`sidebar-menu-item ${subElements?.length ? 'has-children' : ''}`} onClick={closeMobileMenu} activeClassName='active open' {...rest} key={label}> let link = <NavLink className={`sidebar-menu-item ${subElements?.length ? 'has-children' : ''}`} onClick={closeMobileMenu} activeClassName='active open' {...rest} key={label}>
{label}{subElements && <i className="sidebar-menu-item-carrot" onClick={toggleMenu}></i>} {label}{subElements && <i className='sidebar-menu-item-carrot' onClick={toggleMenu}></i>}
</NavLink>; </NavLink>;
if(external) if(external)
link = <Link className='sidebar-menu-item' {...rest}>{label}</Link>; link = <Link className='sidebar-menu-item' {...rest}>{label}</Link>;
@ -102,8 +102,8 @@ const SidebarMenu = ({ menuItems = [], children }: {menuItems: SidebarMenuItem[]
{elements} {elements}
{children} {children}
<div className="parent-menu log-out-menu-item"> <div className='parent-menu log-out-menu-item'>
<a className="sidebar-menu-item" onClick={logOut} href="#">Log Out</a> <a className='sidebar-menu-item' onClick={logOut} href='#'>Log Out</a>
</div> </div>
</div>; </div>;

View File

@ -33,7 +33,7 @@ export const Table = ({ headerItems, children, items, itemKeys }: TableProps) =>
if(!children && !items) if(!children && !items)
throw new Error('Missing items or children'); throw new Error('Missing items or children');
let i = 0; let i = 0;
return <table className="striped hover table-pd" > return <table className='striped hover table-pd' >
<thead> <thead>
<tr> <tr>
{headerItems.map(item => <th key={item}>{item}</th>)} {headerItems.map(item => <th key={item}>{item}</th>)}

View File

@ -12,10 +12,10 @@ type SubtitleContext = {
} }
const Context = React.createContext<SubtitleContext>({ const Context = React.createContext<SubtitleContext>({
breadcrumbs: [], breadcrumbs: [],
set: () => null, set: () => null,
clear: () => null, clear: () => null,
push: () => null, push: () => null,
pop: () => null, pop: () => null,
}); });
let TO: NodeJS.Timeout | null = null; let TO: NodeJS.Timeout | null = null;
@ -30,11 +30,11 @@ export const useSubtitle = () =>
const Main = ({ title, crumbs: crumbs, children }: {title: string, crumbs: string[], children: React.ReactNode}) => const Main = ({ title, crumbs: crumbs, children }: {title: string, crumbs: string[], children: React.ReactNode}) =>
{ {
const trail = crumbs.length ? `/ ${crumbs.join(' / ')}` : ''; const trail = crumbs.length ? `/ ${crumbs.join(' / ')}` : '';
return <div className="page"> return <div className='page'>
<Helmet> <Helmet>
<title>{title} {trail}</title> <title>{title} {trail}</title>
</Helmet> </Helmet>
<h2 className="pageTitle">{title} {trail}</h2> <h2 className='pageTitle'>{title} {trail}</h2>
<div className='card'> <div className='card'>
{children} {children}
</div> </div>

View File

@ -32,15 +32,15 @@ const UserControls = () =>
detailsRef.current.removeAttribute('open'); detailsRef.current.removeAttribute('open');
}}> }}>
<details ref={detailsRef} className='dropdown user-controls card'> <details ref={detailsRef} className='dropdown user-controls card'>
<summary className="is-vertical-align"> <summary className='is-vertical-align'>
Hello {user.displayName || user.name} Hello {user.displayName || user.name}
<img className="profile-picture" src={`/api/users/${user.id}/avatar`}></img> <img className='profile-picture' src={`/api/users/${user.id}/avatar`}></img>
</summary> </summary>
<div className="card"> <div className='card'>
<p className='mb-0'><span className='clickable' onClick={() => navigate('/home/profile')}>Profile</span></p> <p className='mb-0'><span className='clickable' onClick={() => navigate('/home/profile')}>Profile</span></p>
<hr className='mt-3 mb-3'/> <hr className='mt-3 mb-3'/>
<p><a onClick={logOut} className="text-error">Logout</a></p> <p><a onClick={logOut} className='text-error'>Logout</a></p>
</div> </div>
</details> </details>

View File

@ -71,31 +71,31 @@ const CredentialFields = () =>
return <div> return <div>
<LoadingBar color='#2685ff' ref={ref} /> <LoadingBar color='#2685ff' ref={ref} />
<div className="is-center"> <div className='is-center'>
<img className="logoImg mb-4" src={logoImg}></img> <img className='logoImg mb-4' src={logoImg}></img>
</div> </div>
<div className="card mb-3 is-center dir-column"> <div className='card mb-3 is-center dir-column'>
<h2>Log in</h2> <h2>Log in</h2>
<form className="loginForm"> <form className='loginForm'>
<input ref={usernameRef} autoComplete='off' placeholder='Username' required id='username' type='text' autoFocus /> <input ref={usernameRef} autoComplete='off' placeholder='Username' required id='username' type='text' autoFocus />
<input ref={passwordRef} autoComplete='off' placeholder='Password' required id='password' type='password' /> <input ref={passwordRef} autoComplete='off' placeholder='Password' required id='password' type='password' />
<div className='button-group'> <div className='button-group'>
<button className="button primary" onClick={loginClick}>Enter</button> <button className='button primary' onClick={loginClick}>Enter</button>
<button className='button red' onClick={forgotPassword}>Forgot password</button> <button className='button red' onClick={forgotPassword}>Forgot password</button>
</div> </div>
</form> </form>
{registrationEnabled ? <div className="text-center registerText"> {registrationEnabled ? <div className='text-center registerText'>
{ 'Don\'t have an account?'}<br/><a onClick={() => navigate('/register')} className="clickable">Register</a> instead! { 'Don\'t have an account?'}<br/><a onClick={() => navigate('/register')} className='clickable'>Register</a> instead!
</div> : null} </div> : null}
</div> </div>
<div className="card is-center dir-column"> <div className='card is-center dir-column'>
<b>Alternate login methods</b> <b>Alternate login methods</b>
<div className="methodsWrapper is-center flex-wrap"> <div className='methodsWrapper is-center flex-wrap'>
{loginMethods.map((method: OAuthProvider) => <div {loginMethods.map((method: OAuthProvider) => <div
className='third-party-login' className='third-party-login'
key={method.name} key={method.name}
@ -104,7 +104,7 @@ const CredentialFields = () =>
window.location.pathname = `/api/login/${method.name}`; window.location.pathname = `/api/login/${method.name}`;
}}> }}>
<img <img
crossOrigin="anonymous" crossOrigin='anonymous'
alt={method.name} alt={method.name}
src={method.icon} src={method.icon}
width={48} height={48} width={48} height={48}
@ -145,16 +145,16 @@ const TwoFactor = () =>
return <div> return <div>
<LoadingBar color='#2685ff' ref={ref} /> <LoadingBar color='#2685ff' ref={ref} />
<div className="is-center"> <div className='is-center'>
<img className="logoImg mb-4" src={logoImg}></img> <img className='logoImg mb-4' src={logoImg}></img>
</div> </div>
<div className="card mb-3 is-center dir-column"> <div className='card mb-3 is-center dir-column'>
<h2>Verification Code</h2> <h2>Verification Code</h2>
{fail ? <p className="mt-0">Invalid code</p> : null} {fail ? <p className='mt-0'>Invalid code</p> : null}
<form className="is-center dir-column"> <form className='is-center dir-column'>
<input ref={mfaCode} autoComplete='off' placeholder='Your 2FA code...' required id='2faCode' type='password' /> <input ref={mfaCode} autoComplete='off' placeholder='Your 2FA code...' required id='2faCode' type='password' />
<button className="button primary mt-1 mb-3" onClick={twoFactorClick}>Enter</button> <button className='button primary mt-1 mb-3' onClick={twoFactorClick}>Enter</button>
</form> </form>
</div> </div>
</div>; </div>;
@ -162,7 +162,7 @@ const TwoFactor = () =>
const Login = ({ title }: {title: string}) => const Login = ({ title }: {title: string}) =>
{ {
return <div className="row is-center is-full-screen is-marginless"> return <div className='row is-center is-full-screen is-marginless'>
<div className='loginWrapper col-6 col-6-md col-3-lg'> <div className='loginWrapper col-6 col-6-md col-3-lg'>
<Helmet> <Helmet>
<title>{title}</title> <title>{title}</title>

View File

@ -56,8 +56,8 @@ const Main = () =>
const Recover = ({ title }: {title: string}) => const Recover = ({ title }: {title: string}) =>
{ {
return <div className="row is-center is-fucll-screen is-marginless"> return <div className='row is-center is-fucll-screen is-marginless'>
<div className="col-6 col-6-md col-3-lg"> <div className='col-6 col-6-md col-3-lg'>
<Helmet> <Helmet>
<title>{title}</title> <title>{title}</title>
</Helmet> </Helmet>

View File

@ -40,28 +40,28 @@ const Register = ({ title }: {title: string}) =>
navigate('/login'); navigate('/login');
}; };
return <div className="row is-center is-full-screen is-marginless"> return <div className='row is-center is-full-screen is-marginless'>
<LoadingBar color='#2685ff' ref={ref} /> <LoadingBar color='#2685ff' ref={ref} />
<Helmet> <Helmet>
<title>{title}</title> <title>{title}</title>
</Helmet> </Helmet>
<div className='registerWrapper col-6 col-6-md col-3-lg'> <div className='registerWrapper col-6 col-6-md col-3-lg'>
<div> <div>
<div className="is-center"> <div className='is-center'>
<img className="logoImg mb-4" src={logoImg}></img> <img className='logoImg mb-4' src={logoImg}></img>
</div> </div>
<div className="card mb-3 is-center dir-column"> <div className='card mb-3 is-center dir-column'>
<h2>Register</h2> <h2>Register</h2>
<form className="registerForm"> <form className='registerForm'>
<input ref={usernameRef} autoComplete='off' placeholder='Username' required id='username' type='text' autoFocus /> <input ref={usernameRef} autoComplete='off' placeholder='Username' required id='username' type='text' autoFocus />
<input ref={passwordRef} autoComplete='off' placeholder='Password' required id='password' type='password' /> <input ref={passwordRef} autoComplete='off' placeholder='Password' required id='password' type='password' />
<button className="button primary" onClick={submit}>Register</button> <button className='button primary' onClick={submit}>Register</button>
</form> </form>
<div className="text-center registerText"> <div className='text-center registerText'>
Have an account?<br/><a onClick={() => navigate('/login')} className="clickable">Log in</a> instead! Have an account?<br/><a onClick={() => navigate('/login')} className='clickable'>Log in</a> instead!
</div> </div>
</div> </div>
</div> </div>

View File

@ -20,9 +20,9 @@ const Main = () =>
// console.log(file); // console.log(file);
}; };
return <div className="row"> return <div className='row'>
<div className="col-6-lg col-12"> <div className='col-6-lg col-12'>
<h2>Thematic customisation</h2> <h2>Thematic customisation</h2>
<form> <form>
<input type='text' placeholder='Site name' /> <input type='text' placeholder='Site name' />
@ -32,7 +32,7 @@ const Main = () =>
</div> </div>
<div className="col-6-lg col-12"> <div className='col-6-lg col-12'>
<h2>Dingus</h2> <h2>Dingus</h2>
</div> </div>
@ -51,8 +51,8 @@ const Admin = () =>
}, [ window.location.href ]); }, [ window.location.href ]);
return <ErrorBoundary> return <ErrorBoundary>
<Routes> <Routes>
<Route path="/" element={<Main />} /> <Route path='/' element={<Main />} />
<Route path="/users/*" element={<PermissionBarrier permission='administrator:users:*'> <Route path='/users/*' element={<PermissionBarrier permission='administrator:users:*'>
<Users/> <Users/>
</PermissionBarrier>} /> </PermissionBarrier>} />
<Route path='/roles/*' element={<PermissionBarrier permission='administrator:roles:*'> <Route path='/roles/*' element={<PermissionBarrier permission='administrator:roles:*'>

View File

@ -8,10 +8,10 @@ import ClickDetector from '../../util/ClickDetector';
import { useSubtitle } from '../../components/TitledPage'; import { useSubtitle } from '../../components/TitledPage';
const emptyFlag: FlagCreateData = { const emptyFlag: FlagCreateData = {
name: '', name: '',
env: '', env: '',
consumer: '', consumer: '',
value: '', value: '',
hierarchy: '' hierarchy: ''
}; };
@ -251,7 +251,7 @@ const CreateFlag = ({ close, submit }: { close: () => void, submit: (data: FlagC
<h4>Create Flag</h4> <h4>Create Flag</h4>
<form onSubmit={createFlag} onReset={cancel}> <form onSubmit={createFlag} onReset={cancel}>
<label>Name</label> <label>Name</label>
<input onChange={handleChange} minLength={4} name='name' autoComplete='off' placeholder='Name' type='text' required /> <input onChange={handleChange} minLength={4} name='name' autoComplete='off' placeholder='Name' type='text' required />
<label>Environment</label> <label>Environment</label>
<input onChange={handleChange} name='env' autoComplete='off' placeholder='Environment' type='text' required /> <input onChange={handleChange} name='env' autoComplete='off' placeholder='Environment' type='text' required />
<label>Consumer</label> <label>Consumer</label>
@ -362,7 +362,7 @@ const Main = () =>
}} }}
placeholder='Flag name or ID' placeholder='Flag name or ID'
/> />
{availableFilters && <Dropdown className="m-0"> {availableFilters && <Dropdown className='m-0'>
<Dropdown.Header className='p-2'> <Dropdown.Header className='p-2'>
{selectedFilters.length === 0 {selectedFilters.length === 0
? <p className='placeholder'>Click to filter</p> ? <p className='placeholder'>Click to filter</p>
@ -398,7 +398,7 @@ const Main = () =>
<h4 className='mt-3'>Flags</h4> <h4 className='mt-3'>Flags</h4>
<button onClick={() => togglePopup(true)} className='button primary'>Create</button> <button onClick={() => togglePopup(true)} className='button primary'>Create</button>
<ToggleSwitch className="mt-3 mb-3" defaultValue={listView} onChange={(event) => <ToggleSwitch className='mt-3 mb-3' defaultValue={listView} onChange={(event) =>
{ {
toggleListView(event.target.checked); toggleListView(event.target.checked);
}}>List View:</ToggleSwitch> }}>List View:</ToggleSwitch>

View File

@ -16,10 +16,10 @@ type UserFilters = {
// //
} }
const emptyUsersState = { const emptyUsersState = {
users: new Map(), setUsers: () => null, users: new Map(), setUsers: () => null,
roles: new Map(), setRoles: () => null, roles: new Map(), setRoles: () => null,
refreshState: false, refreshUsers: () => null, refreshState: false, refreshUsers: () => null,
searchFilter: {}, setFilter: () => null searchFilter: {}, setFilter: () => null
}; };
type UsersContextObj = { type UsersContextObj = {
users: Map<string, UserStruct>, setUsers: (users: Map<string, UserStruct>) => void, users: Map<string, UserStruct>, setUsers: (users: Map<string, UserStruct>) => void,
@ -313,7 +313,7 @@ const UserData = ({ user, updateUser }: {user: UserStruct | null, updateUser: (u
<Dropdown.Header className='w-25-rem p-0'> <Dropdown.Header className='w-25-rem p-0'>
{equippedRoles.map(role => {equippedRoles.map(role =>
<div key={role.id} className='card role flex gap-5px align-items-center'> <div key={role.id} className='card role flex gap-5px align-items-center'>
{role.name} <span className="icon x hover" onClick={(e) => {role.name} <span className='icon x hover' onClick={(e) =>
{ {
e.preventDefault(); e.preventDefault();
deselectRole(role); deselectRole(role);
@ -345,7 +345,7 @@ const UserData = ({ user, updateUser }: {user: UserStruct | null, updateUser: (u
</div> </div>
<hr /> <hr />
<div className='ml-4'> <div className='ml-4'>
<button onClick={commitPerms} className="button primary">Save</button> <button onClick={commitPerms} className='button primary'>Save</button>
<button onClick={resetPerms} className='button red'>Reset</button> <button onClick={resetPerms} className='button red'>Reset</button>
</div> </div>
</div> </div>
@ -504,15 +504,15 @@ const UserList = ({ page, pages, setPage, loadState, onRefresh }: UserListProps)
<h4>Invitation Link</h4> <h4>Invitation Link</h4>
{ {
link ? link ?
<div className="registerCodeWrapper tooltip"><p onClick={copyToClipboard}>{link}</p></div> <div className='registerCodeWrapper tooltip'><p onClick={copyToClipboard}>{link}</p></div>
: <button onClick={getSignupCode} className="button primary is-center">Create sign-up link</button> : <button onClick={getSignupCode} className='button primary is-center'>Create sign-up link</button>
} }
<hr /> <hr />
<h4>Create User</h4> <h4>Create User</h4>
<form> <form>
<p>Users will be forced to change the password you set here.</p> <p>Users will be forced to change the password you set here.</p>
<input ref={usernameRef} placeholder="Username" autoComplete="off" type='text' id='username' /> <input ref={usernameRef} placeholder='Username' autoComplete='off' type='text' id='username' />
<input ref={passwordRef} placeholder="Password" autoComplete="off" type='password' id='password' /> <input ref={passwordRef} placeholder='Password' autoComplete='off' type='password' id='password' />
<button onClick={createUser} className='button primary'>Create User</button> <button onClick={createUser} className='button primary'>Create User</button>
</form> </form>
</div> </div>
@ -558,7 +558,7 @@ const Main = () =>
}, [ refresh, setRoles ]); }, [ refresh, setRoles ]);
return <Routes> return <Routes>
<Route path='/*' element={<UserList {...{ page, pages, setPage, loadState, onRefresh: () => setRefresh(val => !val) }} />} /> <Route path='/*' element={<UserList {...{ page, pages, setPage, loadState, onRefresh: () => setRefresh(val => !val) }} />} />
<Route path='/:userId/*' element={<User refreshList={() => setRefresh(val => !val)} />} /> <Route path='/:userId/*' element={<User refreshList={() => setRefresh(val => !val)} />} />
{/* <Route path='/:userId/applications/:appId' element={<Application />} /> */} {/* <Route path='/:userId/applications/:appId' element={<Application />} /> */}
</Routes>; </Routes>;

View File

@ -182,7 +182,7 @@ const Applications = () =>
const Main = () => const Main = () =>
{ {
return <div className="row"> return <div className='row'>
<PaginatedCard <PaginatedCard
path='/api/user/applications' path='/api/user/applications'
@ -215,12 +215,12 @@ const Applications = () =>
</Table> </Table>
</div> */} </div> */}
<div className="col"> <div className='col'>
<h2>Create Application</h2> <h2>Create Application</h2>
<form> <form>
<input ref={nameField} placeholder="Name" type='text' /> <input ref={nameField} placeholder='Name' type='text' />
<textarea ref={descField} rows={5} placeholder="Describe your application" /> <textarea ref={descField} rows={5} placeholder='Describe your application' />
<button onClick={createApp} className="button primary mt-3">Create</button> <button onClick={createApp} className='button primary mt-3'>Create</button>
</form> </form>
</div> </div>
</div>; </div>;
@ -237,8 +237,8 @@ const Applications = () =>
return <ErrorBoundary> return <ErrorBoundary>
<Routes> <Routes>
<Route path="/" element={<Main />} /> <Route path='/' element={<Main />} />
<Route path="/:id" element={<Application />} /> <Route path='/:id' element={<Application />} />
</Routes> </Routes>
</ErrorBoundary>; </ErrorBoundary>;
}; };

View File

@ -49,9 +49,9 @@ const Home = () =>
}, [ window.location.href ]); }, [ window.location.href ]);
return <ErrorBoundary> return <ErrorBoundary>
<Routes> <Routes>
<Route path="/" element={<Main />} /> <Route path='/' element={<Main />} />
<Route path="/profile" element={<Profile />} /> <Route path='/profile' element={<Profile />} />
<Route path="/applications/*" element={ <Route path='/applications/*' element={
<PermissionBarrier permission='applications:*'> <PermissionBarrier permission='applications:*'>
<Applications /> <Applications />
</PermissionBarrier> </PermissionBarrier>

View File

@ -104,6 +104,12 @@ const Profile = () =>
const newPassRef = useRef<HTMLInputElement>(null); const newPassRef = useRef<HTMLInputElement>(null);
const newPassRepeatRef = useRef<HTMLInputElement>(null); const newPassRepeatRef = useRef<HTMLInputElement>(null);
useEffect(() =>
{
subtitle.set('Profile');
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (!user) if (!user)
return <div> return <div>
Not logged in Not logged in
@ -170,11 +176,6 @@ const Profile = () =>
window.open('/api/user/connect/discord', '_blank', 'noreferrer'); window.open('/api/user/connect/discord', '_blank', 'noreferrer');
}; };
useEffect(() =>
{
subtitle.set('Profile');
}, []);
return <div> return <div>
<div className='row'> <div className='row'>
<DataCard className='col-6-lg col-12'> <DataCard className='col-6-lg col-12'>

View File

@ -1,7 +1,7 @@
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef } from 'react';
// Listens for mouse clicks outside of the wrapped element // Listens for mouse clicks outside of the wrapped element
const alerter = (ref: React.RefObject<HTMLElement>, callback: () => void) => const useAlerter = (ref: React.RefObject<HTMLElement>, callback: () => void) =>
{ {
useEffect(() => useEffect(() =>
{ {
@ -20,7 +20,7 @@ const alerter = (ref: React.RefObject<HTMLElement>, callback: () => void) =>
document.removeEventListener('mousedown', listener); document.removeEventListener('mousedown', listener);
}; };
}, [ ref ]); }, [ callback, ref ]);
}; };
/** /**
@ -32,7 +32,7 @@ const alerter = (ref: React.RefObject<HTMLElement>, callback: () => void) =>
const ClickDetector = ({ children, callback, className='', style }: { style?: React.CSSProperties, children: React.ReactNode, callback: () => void, className?: string}) => const ClickDetector = ({ children, callback, className='', style }: { style?: React.CSSProperties, children: React.ReactNode, callback: () => void, className?: string}) =>
{ {
const wrapperRef = useRef(null); const wrapperRef = useRef(null);
alerter(wrapperRef, callback); useAlerter(wrapperRef, callback);
return ( return (
<div style={style} className={`click-detector ${className}`} ref={wrapperRef}> <div style={style} className={`click-detector ${className}`} ref={wrapperRef}>

View File

@ -23,11 +23,11 @@ class ErrorBoundary extends React.Component<BoundaryProps, StateProps>
{ {
super(props); super(props);
this.state = { this.state = {
reAuth: false, reAuth: false,
chunkIssue: false, chunkIssue: false,
active: false, active: false,
error: null, error: null,
info: null info: null
}; };
this.fallback = props.fallback; this.fallback = props.fallback;
} }

View File

@ -347,7 +347,7 @@ export const dateString = (ts: number) =>
return new Date(ts).toLocaleString(navigator.language); return new Date(ts).toLocaleString(navigator.language);
}; };
export const randomString = (len = 32) => export const randomString = (len = 32) =>
{ {
let result = ''; let result = '';
for (let i = 50; i > 0; --i) for (let i = 50; i > 0; --i)

View File

@ -15,7 +15,7 @@ export const Permission = ({ name, value, chain, updatePerms, readOnly = false }
updatePerms(chain, val); updatePerms(chain, val);
}; };
return <li className="flex is-vertical-align space-between"> return <li className='flex is-vertical-align space-between'>
<label>{name}</label> <label>{name}</label>
<input readOnly={readOnly} ref={inputRef} onChange={onChange} max={10} min={0} type='number' defaultValue={value as number}></input> <input readOnly={readOnly} ref={inputRef} onChange={onChange} max={10} min={0} type='number' defaultValue={value as number}></input>
</li>; </li>;
@ -36,9 +36,9 @@ export const PermissionGroup = ({ name, value, chain, updatePerms, readOnly = fa
elements.push(<Permission {...props} />); elements.push(<Permission {...props} />);
} }
return <li> return <li>
<input type="checkbox" className="collapsible" id={`${chain}_${name}_collapsible`}></input> <input type='checkbox' className='collapsible' id={`${chain}_${name}_collapsible`}></input>
<label htmlFor={`${chain}_${name}_collapsible`} > <label htmlFor={`${chain}_${name}_collapsible`} >
<div className="groupName"> <div className='groupName'>
<b>Group: {name}</b> <b>Group: {name}</b>
</div> </div>
</label> </label>
@ -97,7 +97,7 @@ export const Permissions = ({ perms, onUpdate }: { perms: PermissionsStruct, onU
elements.push(<Elem {...props} />); elements.push(<Elem {...props} />);
} }
return <ul className="tree w-max-fit-content w-min-35-rem"> return <ul className='tree w-max-fit-content w-min-35-rem'>
{elements} {elements}
</ul>; </ul>;
}; };

View File

@ -10,7 +10,7 @@ const RateLimit = ({ route, limit }: {route: string, limit: RL}) =>
<label>Time</label> <label>Time</label>
<input min={0} defaultValue={limit.time} type='number' /> <input min={0} defaultValue={limit.time} type='number' />
<label>Enabled</label> <label>Enabled</label>
<div className="check-box"> <div className='check-box'>
<input defaultChecked={!limit.disabled} type='checkbox' /> <input defaultChecked={!limit.disabled} type='checkbox' />
</div> </div>
</Fragment>; </Fragment>;
@ -21,14 +21,14 @@ export const RateLimits = ({ rateLimits }: {rateLimits: RLs}) =>
const routes = Object.keys(rateLimits); const routes = Object.keys(rateLimits);
const elements = routes.map((route, index) => const elements = routes.map((route, index) =>
{ {
return <div key={index} className="card"> return <div key={index} className='card'>
<RateLimit {...{ route, limit:rateLimits[route], index }} /> <RateLimit {...{ route, limit: rateLimits[route], index }} />
</div>; </div>;
}); });
return <div className='col-6-lg col-12'> return <div className='col-6-lg col-12'>
<h2>Rate Limits</h2> <h2>Rate Limits</h2>
<div className="flex flex-wrap"> <div className='flex flex-wrap'>
{elements} {elements}
</div> </div>