Update linter rules

This commit is contained in:
Erik 2024-04-06 12:55:26 +03:00
parent c7b879a5f3
commit e68de7f432
5 changed files with 72 additions and 42 deletions

View File

@ -7,7 +7,8 @@
"extends": [ "extends": [
"eslint:recommended", "eslint:recommended",
"plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended",
"plugin:react/recommended" "plugin:react/recommended",
"plugin:react-hooks/recommended"
], ],
"parserOptions": { "parserOptions": {
"ecmaFeatures": { "ecmaFeatures": {
@ -17,7 +18,8 @@
"sourceType": "module" "sourceType": "module"
}, },
"plugins": [ "plugins": [
"react" "react",
"react-hooks"
], ],
"rules": { "rules": {
"nonblock-statement-body-position": [ "nonblock-statement-body-position": [

View File

@ -4,14 +4,18 @@ import { Helmet } from 'react-helmet-async';
// import socket from '../util/Socket'; // import socket from '../util/Socket';
type SubtitleContext = { type SubtitleContext = {
subtitle: string | null, breadcrumbs: string[],
set: (name: string) => void, set: (name: string) => void,
clear: () => void clear: () => void,
push: (crumb: string) => void,
pop: () => void,
} }
const Context = React.createContext<SubtitleContext>({ const Context = React.createContext<SubtitleContext>({
subtitle: null, breadcrumbs: [],
set: () => null, set: () => null,
clear: () => null clear: () => null,
push: () => null,
pop: () => null,
}); });
let TO: NodeJS.Timeout | null = null; let TO: NodeJS.Timeout | null = null;
@ -23,13 +27,14 @@ export const useSubtitle = () =>
return useContext(Context); return useContext(Context);
}; };
const Main = ({ title, subtitle, children }: {title: string, subtitle?: string | null, children: React.ReactNode}) => const Main = ({ title, crumbs: crumbs, children }: {title: string, crumbs: string[], children: React.ReactNode}) =>
{ {
const trail = crumbs.length ? `/ ${crumbs.join(' / ')}` : '';
return <div className="page"> return <div className="page">
<Helmet> <Helmet>
<title>{title} { subtitle ? `/ ${subtitle}` : ''}</title> <title>{title} {trail}</title>
</Helmet> </Helmet>
<h2 className="pageTitle">{title} { subtitle ? `/ ${subtitle}` : ''}</h2> <h2 className="pageTitle">{title} {trail}</h2>
<div className='card'> <div className='card'>
{children} {children}
</div> </div>
@ -39,23 +44,42 @@ const Main = ({ title, subtitle, children }: {title: string, subtitle?: string |
const TitledPage = ({ title, children }: {title: string, children: React.ReactNode}) => const TitledPage = ({ title, children }: {title: string, children: React.ReactNode}) =>
{ {
// let subtitle: string | null = null; // let subtitle: string | null = null;
const [ subtitle, setSubtitle ] = useState<string | null>(null); const [ trail, setTrail ] = useState<string []>([]);
let page = `${title}`; let page = `${title}`;
if (subtitle) if (trail.length)
page += ` / ${subtitle}`; page += ` / ${trail.join(' / ')}`;
const onlineState = { page, url: window.location.href, state: 'Online' }; const onlineState = { page, url: window.location.href, state: 'Online' };
const set = (str: string) => const set = (str: string) =>
{ {
// subtitle = str; // subtitle = str;
// console.log('set subtitle', str); // console.log('set subtitle', str);
setSubtitle(() => str); setTrail(() => [ str ]);
}; };
const clear = () => const clear = () =>
{ {
// subtitle = null; // subtitle = null;
// console.log('clear'); // console.log('clear');
setSubtitle(null); setTrail([]);
};
const push = (name: string) =>
{
// console.log('push', name);
setTrail(trail =>
{
return [ ...trail, name ];
});
};
const pop = () =>
{
setTrail(trail =>
{
trail.pop();
// console.log('pop', name);
return [ ...trail ];
});
}; };
const setAfk = () => const setAfk = () =>
@ -115,10 +139,11 @@ const TitledPage = ({ title, children }: {title: string, children: React.ReactNo
document.removeEventListener('keypress', activityListener); document.removeEventListener('keypress', activityListener);
document.removeEventListener('visibilitychange', visibilityListener); document.removeEventListener('visibilitychange', visibilityListener);
}; };
}, [ title, subtitle ]); // eslint-disable-next-line react-hooks/exhaustive-deps
}, [ title, trail ]);
return <Context.Provider value={{ subtitle: null, set, clear }}> return <Context.Provider value={{ breadcrumbs: trail, set, push, pop, clear }}>
<Main title={title} subtitle={subtitle}> <Main title={title} crumbs={trail}>
{children} {children}
</Main> </Main>
</Context.Provider>; </Context.Provider>;

View File

@ -47,6 +47,7 @@ const Admin = () =>
{ {
if(window.location.href.endsWith('/admin')) if(window.location.href.endsWith('/admin'))
subtitle.clear(); subtitle.clear();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ window.location.href ]); }, [ window.location.href ]);
return <ErrorBoundary> return <ErrorBoundary>
<Routes> <Routes>

View File

@ -33,24 +33,23 @@ const Role = ({ refreshList }: RoleProps) =>
const [ role, setRole ] = useState<RoleStruct | null>(roleId ? roles.get(roleId) ?? null : null); const [ role, setRole ] = useState<RoleStruct | null>(roleId ? roles.get(roleId) ?? null : null);
const [ refresh, setRefresh ] = useState(false); const [ refresh, setRefresh ] = useState(false);
if (!roleId)
return <div>
<BackButton />
<p>Invalid userId</p>
</div>;
useEffect(() => useEffect(() =>
{ {
if (!role) if (!role)
(async () => (async () =>
{ {
const response = await get(`/api/roles/${roleId}`); const response = await get<RoleStruct>(`/api/roles/${roleId}`);
if (!response.success || !response.data) if (!response.success || !response.data)
return errorToast(response.message); return errorToast(response.message);
setRole(response.data as RoleStruct); setRole(response.data);
})(); })();
}, [ roleId ]); }, [ role, roleId ]);
if (!roleId)
return <div>
<BackButton />
<p>Invalid userId</p>
</div>;
if (!role) if (!role)
return <div> return <div>
@ -308,7 +307,7 @@ const Main = () =>
setRoles(new Map(response.data.roles.map((role) => [ role.id, role ]))); setRoles(new Map(response.data.roles.map((role) => [ role.id, role ])));
setLoadState(RefresherState.success); setLoadState(RefresherState.success);
})(); })();
}, [ page, filters, refresh ]); }, [ page, filters, refresh, setRoles ]);
return <Routes> return <Routes>
<Route path='/*' element={<RoleList {...{ page, pages, setPage, loadState, filterUpdate: setFilters, onRefresh: () => setRefresh(val => !val) }} />} /> <Route path='/*' element={<RoleList {...{ page, pages, setPage, loadState, filterUpdate: setFilters, onRefresh: () => setRefresh(val => !val) }} />} />
@ -322,7 +321,8 @@ const Roles = () =>
useEffect(() => useEffect(() =>
{ {
subtitle.set('Roles'); subtitle.set('Roles');
}); // eslint-disable-next-line react-hooks/exhaustive-deps
}, [ ]);
return <ErrorBoundary> return <ErrorBoundary>
<RolesContext> <RolesContext>
<Main /> <Main />

View File

@ -359,16 +359,11 @@ type UserProps = {
} }
const User = ({ refreshList }: UserProps) => const User = ({ refreshList }: UserProps) =>
{ {
// const subtitle = useSubtitle();
const { users, refreshState } = useContext(Context); const { users, refreshState } = useContext(Context);
const { userId } = useParams(); const { userId } = useParams();
if (!userId) const [ user, setUser ] = useState<UserStruct | null>(users.get(userId ?? '') ?? null);
return <div>
<BackButton />
<p>Invalid userId</p>
</div>;
const [ user, setUser ] = useState<UserStruct | null>(users.get(userId) ?? null);
const [ applications, setApplications ] = useState<Map<string, ApplicationStruct>>(new Map()); const [ applications, setApplications ] = useState<Map<string, ApplicationStruct>>(new Map());
useEffect(() => useEffect(() =>
@ -376,12 +371,18 @@ const User = ({ refreshList }: UserProps) =>
if (!user) if (!user)
(async () => (async () =>
{ {
const response = await get(`/api/users/${userId}`); const response = await get<UserStruct>(`/api/users/${userId}`);
if (!response.success || !response.data) if (!response.success || !response.data)
return errorToast(response.message); return errorToast(response.message);
setUser(response.data as UserStruct); setUser(response.data);
})(); })();
}, [ userId, refreshState ]); }, [ userId, refreshState, user ]);
if (!userId)
return <div>
<BackButton />
<p>Invalid userId</p>
</div>;
return <Routes> return <Routes>
<Route path='/' element={<UserData user={user} updateUser={(user) => <Route path='/' element={<UserData user={user} updateUser={(user) =>
@ -543,7 +544,7 @@ const Main = () =>
setUsers(new Map(response.data.users.map((user) => [ user.id, user ]))); setUsers(new Map(response.data.users.map((user) => [ user.id, user ])));
setLoadState(RefresherState.success); setLoadState(RefresherState.success);
})(); })();
}, [ page, searchFilter, refresh ]); }, [ page, searchFilter, refresh, setUsers ]);
useEffect(() => useEffect(() =>
{ {
@ -554,7 +555,7 @@ const Main = () =>
return errorToast(response.message); return errorToast(response.message);
setRoles(new Map(response.data.roles.map((role) => [ role.id, role ]))); setRoles(new Map(response.data.roles.map((role) => [ role.id, role ])));
})(); })();
}, [ refresh ]); }, [ 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) }} />} />
@ -569,7 +570,8 @@ const Users = () =>
useEffect(() => useEffect(() =>
{ {
subtitle.set('Users'); subtitle.set('Users');
}); // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return <ErrorBoundary> return <ErrorBoundary>
<UsersContext> <UsersContext>
<Main/> <Main/>