Browse Source

chore: fix eslint warinings

Nicolas Meienberger 2 years ago
parent
commit
6dbc831624

+ 2 - 1
.eslintrc.js

@@ -1,5 +1,5 @@
 module.exports = {
 module.exports = {
-  plugins: ['@typescript-eslint', 'import', 'react', 'jest', 'jsdoc'],
+  plugins: ['@typescript-eslint', 'import', 'react', 'jest', 'jsdoc', 'jsx-a11y'],
   extends: [
   extends: [
     'plugin:@typescript-eslint/recommended',
     'plugin:@typescript-eslint/recommended',
     'next/core-web-vitals',
     'next/core-web-vitals',
@@ -11,6 +11,7 @@ module.exports = {
     'prettier',
     'prettier',
     'plugin:react/recommended',
     'plugin:react/recommended',
     'plugin:jsdoc/recommended',
     'plugin:jsdoc/recommended',
+    'plugin:jsx-a11y/recommended',
   ],
   ],
   parser: '@typescript-eslint/parser',
   parser: '@typescript-eslint/parser',
   parserOptions: {
   parserOptions: {

+ 3 - 3
src/client/components/Layout/Layout.tsx

@@ -19,7 +19,7 @@ interface IProps {
 
 
 export const Layout: React.FC<IProps> = ({ children, breadcrumbs, title, actions }) => {
 export const Layout: React.FC<IProps> = ({ children, breadcrumbs, title, actions }) => {
   const router = useRouter();
   const router = useRouter();
-  const refreshToken = trpc.auth.refreshToken.useMutation({
+  const { mutate } = trpc.auth.refreshToken.useMutation({
     onSuccess: (data) => {
     onSuccess: (data) => {
       if (data?.token) localStorage.setItem('token', data.token);
       if (data?.token) localStorage.setItem('token', data.token);
     },
     },
@@ -30,8 +30,8 @@ export const Layout: React.FC<IProps> = ({ children, breadcrumbs, title, actions
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
-    refreshToken.mutate();
-  }, []);
+    mutate();
+  }, [mutate]);
 
 
   const { version } = useSystemStore();
   const { version } = useSystemStore();
   const defaultVersion = '0.0.0';
   const defaultVersion = '0.0.0';

+ 1 - 1
src/client/mocks/fixtures/app.fixtures.ts

@@ -5,7 +5,7 @@ import { App, AppCategory, AppInfo, AppWithInfo } from '../../core/types';
 const randomCategory = (): AppCategory[] => {
 const randomCategory = (): AppCategory[] => {
   const categories = Object.values(APP_CATEGORIES);
   const categories = Object.values(APP_CATEGORIES);
   const randomIndex = faker.datatype.number({ min: 0, max: categories.length - 1 });
   const randomIndex = faker.datatype.number({ min: 0, max: categories.length - 1 });
-  return [categories[randomIndex]!];
+  return [categories[randomIndex] as AppCategory];
 };
 };
 
 
 export const createApp = (overrides?: Partial<AppInfo>): AppInfo => {
 export const createApp = (overrides?: Partial<AppInfo>): AppInfo => {

+ 1 - 1
src/client/mocks/getTrpcMock.ts

@@ -25,7 +25,7 @@ export type RpcErrorResponse = {
   };
   };
 };
 };
 
 
-const jsonRpcSuccessResponse = (data: unknown): RpcSuccessResponse<any> => {
+const jsonRpcSuccessResponse = (data: unknown): RpcSuccessResponse<unknown> => {
   const response = SuperJSON.serialize(data);
   const response = SuperJSON.serialize(data);
 
 
   return {
   return {

+ 3 - 0
src/client/mocks/index.ts

@@ -1,3 +1,6 @@
+/**
+ * This file is the entry point for the mock service worker.
+ */
 async function initMocks() {
 async function initMocks() {
   if (typeof window === 'undefined') {
   if (typeof window === 'undefined') {
     const { server } = await import('./server');
     const { server } = await import('./server');

+ 6 - 6
src/client/modules/AppStore/components/CategorySelector/CategorySelector.tsx

@@ -36,28 +36,28 @@ const CategorySelector: React.FC<IProps> = ({ onSelect, className, initialValue
       className={className}
       className={className}
       value={value}
       value={value}
       styles={{
       styles={{
-        menu: (provided: any) => ({
+        menu: (provided: object) => ({
           ...provided,
           ...provided,
           backgroundColor: bgColor,
           backgroundColor: bgColor,
           color,
           color,
         }),
         }),
-        control: (provided: any) => ({
+        control: (provided: object) => ({
           ...provided,
           ...provided,
           backgroundColor: bgColor,
           backgroundColor: bgColor,
           color,
           color,
           borderColor,
           borderColor,
         }),
         }),
-        option: (provided: any, state: any) => ({
+        option: (provided: object, state: { isFocused: boolean }) => ({
           ...provided,
           ...provided,
           backgroundColor: state.isFocused ? '#243049' : bgColor,
           backgroundColor: state.isFocused ? '#243049' : bgColor,
           color: state.isFocused ? '#fff' : color,
           color: state.isFocused ? '#fff' : color,
         }),
         }),
-        singleValue: (provided: any) => ({
+        singleValue: (provided: object) => ({
           ...provided,
           ...provided,
           color,
           color,
           fontSize: '0.8rem',
           fontSize: '0.8rem',
         }),
         }),
-        placeholder: (provided: any) => ({
+        placeholder: (provided: object) => ({
           ...provided,
           ...provided,
           color: '#a5a9b1',
           color: '#a5a9b1',
           fontSize: '0.8rem',
           fontSize: '0.8rem',
@@ -66,7 +66,7 @@ const CategorySelector: React.FC<IProps> = ({ onSelect, className, initialValue
       onChange={handleChange}
       onChange={handleChange}
       defaultValue={[]}
       defaultValue={[]}
       name="categories"
       name="categories"
-      options={options as any}
+      options={options}
       placeholder="Category"
       placeholder="Category"
     />
     />
   );
   );

+ 5 - 0
src/client/utils/trpc.ts

@@ -3,6 +3,11 @@ import { createTRPCNext } from '@trpc/next';
 import superjson from 'superjson';
 import superjson from 'superjson';
 import type { AppRouter } from '../../server/routers/_app';
 import type { AppRouter } from '../../server/routers/_app';
 
 
+/**
+ * Get base url for the current environment
+ *
+ * @returns {string} base url
+ */
 function getBaseUrl() {
 function getBaseUrl() {
   if (typeof window !== 'undefined') {
   if (typeof window !== 'undefined') {
     // browser should use relative path
     // browser should use relative path

+ 6 - 0
src/client/utils/typescript.ts

@@ -1,5 +1,11 @@
 const objectKeys = <T extends object>(obj: T): (keyof T)[] => Object.keys(obj) as (keyof T)[];
 const objectKeys = <T extends object>(obj: T): (keyof T)[] => Object.keys(obj) as (keyof T)[];
 
 
+/**
+ * Type guard to check if a value is not null or undefined
+ *
+ * @param {any} value - The value to check
+ * @returns {value is NonNullable<any>} - True if the value is not null or undefined
+ */
 function nonNullable<T>(value: T): value is NonNullable<T> {
 function nonNullable<T>(value: T): value is NonNullable<T> {
   return value !== null && value !== undefined;
   return value !== null && value !== undefined;
 }
 }

+ 6 - 0
src/pages/_app.tsx

@@ -11,6 +11,12 @@ import { StatusProvider } from '../client/components/hoc/StatusProvider';
 import { trpc } from '../client/utils/trpc';
 import { trpc } from '../client/utils/trpc';
 import { SystemStatus, useSystemStore } from '../client/state/systemStore';
 import { SystemStatus, useSystemStore } from '../client/state/systemStore';
 
 
+/**
+ * Next.js App component
+ *
+ * @param {AppProps} props - props passed to the app
+ * @returns {JSX.Element} - JSX element
+ */
 function MyApp({ Component, pageProps }: AppProps) {
 function MyApp({ Component, pageProps }: AppProps) {
   const { setDarkMode } = useUIStore();
   const { setDarkMode } = useUIStore();
   const { setStatus, setVersion, pollStatus } = useSystemStore();
   const { setStatus, setVersion, pollStatus } = useSystemStore();

+ 5 - 0
src/pages/_document.tsx

@@ -3,6 +3,11 @@ import { Html, Head, Main, NextScript } from 'next/document';
 
 
 import { getUrl } from '../client/core/helpers/url-helpers';
 import { getUrl } from '../client/core/helpers/url-helpers';
 
 
+/**
+ * Next.js Document component
+ *
+ * @returns {JSX.Element} - JSX element
+ */
 export default function MyDocument() {
 export default function MyDocument() {
   return (
   return (
     <Html lang="en">
     <Html lang="en">

+ 8 - 4
src/server/context.ts

@@ -11,19 +11,23 @@ type CreateContextOptions = {
   session: Session | null;
   session: Session | null;
 };
 };
 
 
-/** Use this helper for:
+/**
+ * Use this helper for:
  * - testing, so we dont have to mock Next.js' req/res
  * - testing, so we dont have to mock Next.js' req/res
  * - trpc's `createSSGHelpers` where we don't have req/res
  * - trpc's `createSSGHelpers` where we don't have req/res
+ *
+ * @param {CreateContextOptions} opts - options
  * @see https://create.t3.gg/en/usage/trpc#-servertrpccontextts
  * @see https://create.t3.gg/en/usage/trpc#-servertrpccontextts
- * */
+ */
 export const createContextInner = async (opts: CreateContextOptions) => ({
 export const createContextInner = async (opts: CreateContextOptions) => ({
   session: opts.session,
   session: opts.session,
 });
 });
 
 
 /**
 /**
  * This is the actual context you'll use in your router
  * This is the actual context you'll use in your router
- * @link https://trpc.io/docs/context
- * */
+ *
+ * @param {CreateNextContextOptions} opts - options
+ */
 export const createContext = async (opts: CreateNextContextOptions) => {
 export const createContext = async (opts: CreateNextContextOptions) => {
   const { req, res } = opts;
   const { req, res } = opts;
 
 

+ 0 - 3
src/server/core/EventDispatcher/EventDispatcher.test.ts

@@ -1,6 +1,3 @@
-/**
- * @jest-environment node
- */
 import fs from 'fs-extra';
 import fs from 'fs-extra';
 import { EventDispatcher } from '.';
 import { EventDispatcher } from '.';
 
 

+ 3 - 1
src/server/core/EventDispatcher/EventDispatcher.ts

@@ -94,6 +94,8 @@ class EventDispatcher {
 
 
   /**
   /**
    * Poll queue and run events
    * Poll queue and run events
+   *
+   * @returns {NodeJS.Timer} - Interval timer
    */
    */
   private pollQueue() {
   private pollQueue() {
     Logger.info(`EventDispatcher(${this.dispatcherId}): Polling queue...`);
     Logger.info(`EventDispatcher(${this.dispatcherId}): Polling queue...`);
@@ -207,7 +209,7 @@ class EventDispatcher {
    *
    *
    * @param {EventType} type - Event type
    * @param {EventType} type - Event type
    * @param {[string[]]} args - Event arguments
    * @param {[string[]]} args - Event arguments
-   * @returns - Promise that resolves when the event is done
+   * @returns {Promise<{ success: boolean; stdout?: string }>} - Promise that resolves when the event is done
    */
    */
   public async dispatchEventAsync(type: EventType, args?: string[]): Promise<{ success: boolean; stdout?: string }> {
   public async dispatchEventAsync(type: EventType, args?: string[]): Promise<{ success: boolean; stdout?: string }> {
     const event = this.dispatchEvent(type, args);
     const event = this.dispatchEvent(type, args);

+ 0 - 2
src/server/core/TipiConfig/TipiConfig.ts

@@ -95,13 +95,11 @@ export class TipiConfig {
         this.config = parsedConfig.data;
         this.config = parsedConfig.data;
       } else {
       } else {
         const errors = formatErrors(parsedConfig.error.flatten());
         const errors = formatErrors(parsedConfig.error.flatten());
-        console.error(`❌ Invalid env config\n${errors}`);
         Logger.error(`❌ Invalid env config\n\n${errors}`);
         Logger.error(`❌ Invalid env config\n\n${errors}`);
         throw new Error('Invalid env config');
         throw new Error('Invalid env config');
       }
       }
     } else {
     } else {
       const errors = formatErrors(parsedFileConfig.error.flatten());
       const errors = formatErrors(parsedFileConfig.error.flatten());
-      console.error(`❌ Invalid settings.json file:\n${errors}`);
       Logger.error(`❌ Invalid settings.json file:\n${errors}`);
       Logger.error(`❌ Invalid settings.json file:\n${errors}`);
       throw new Error('Invalid settings.json file');
       throw new Error('Invalid settings.json file');
     }
     }

+ 1 - 1
src/server/index.ts

@@ -36,7 +36,7 @@ nextApp.prepare().then(async () => {
   app.use('/static', express.static(`${getConfig().rootFolder}/repos/${getConfig().appsRepoId}/`));
   app.use('/static', express.static(`${getConfig().rootFolder}/repos/${getConfig().appsRepoId}/`));
 
 
   app.all('*', (req, res) => {
   app.all('*', (req, res) => {
-    const parsedUrl = parse(req.url!, true);
+    const parsedUrl = parse(req.url, true);
 
 
     handle(req, res, parsedUrl);
     handle(req, res, parsedUrl);
   });
   });

+ 3 - 4
src/server/services/apps/apps.helpers.ts

@@ -212,9 +212,9 @@ export const generateEnvFile = (app: App) => {
   This function reads the apps directory and skips certain system files, then reads the config.json and metadata/description.md files for each app,
   This function reads the apps directory and skips certain system files, then reads the config.json and metadata/description.md files for each app,
   parses the config file, filters out any apps that are not available and returns an array of app information.
   parses the config file, filters out any apps that are not available and returns an array of app information.
   If the config.json file is invalid, it logs an error message.
   If the config.json file is invalid, it logs an error message.
-
+ 
   @returns {Promise<AppInfo[]>} - Returns a promise that resolves with an array of available apps' information.
   @returns {Promise<AppInfo[]>} - Returns a promise that resolves with an array of available apps' information.
-*/
+ */
 export const getAvailableApps = async () => {
 export const getAvailableApps = async () => {
   const appsDir = readdirSync(`/runtipi/repos/${getConfig().appsRepoId}/apps`);
   const appsDir = readdirSync(`/runtipi/repos/${getConfig().appsRepoId}/apps`);
 
 
@@ -248,7 +248,6 @@ export const getAvailableApps = async () => {
  *  If the app is not found, it returns null.
  *  If the app is not found, it returns null.
  *
  *
  *  @param {string} id - The app id.
  *  @param {string} id - The app id.
- *  @param {number} [version] - The current version of the app.
  *  @returns {Promise<{current: number, latest: number, dockerVersion: string} | null>} - Returns an object containing information about the updates available for the app or null if the app is not found or has an invalid config.json file.
  *  @returns {Promise<{current: number, latest: number, dockerVersion: string} | null>} - Returns an object containing information about the updates available for the app or null if the app is not found or has an invalid config.json file.
  */
  */
 export const getUpdateInfo = (id: string) => {
 export const getUpdateInfo = (id: string) => {
@@ -273,7 +272,7 @@ export const getUpdateInfo = (id: string) => {
  *  If an error occurs during the process, it logs the error message and throws an error.
  *  If an error occurs during the process, it logs the error message and throws an error.
  *
  *
  *  @param {string} id - The app id.
  *  @param {string} id - The app id.
- *  @param {AppStatus} [status] - The app status.
+ *  @param {App['status']} [status] - The app status.
  *  @returns {AppInfo | null} - Returns an object with app information or null if the app is not found.
  *  @returns {AppInfo | null} - Returns an object with app information or null if the app is not found.
  */
  */
 export const getAppInfo = (id: string, status?: App['status']) => {
 export const getAppInfo = (id: string, status?: App['status']) => {

+ 1 - 1
src/server/services/system/system.service.ts

@@ -39,7 +39,7 @@ export class SystemServiceClass {
   /**
   /**
    * Get the current and latest version of Tipi
    * Get the current and latest version of Tipi
    *
    *
-   * @returns {Promise<{ current: string; latest: string }>}
+   * @returns {Promise<{ current: string; latest: string }>} The current and latest version
    */
    */
   public getVersion = async (): Promise<{ current: string; latest?: string }> => {
   public getVersion = async (): Promise<{ current: string; latest?: string }> => {
     try {
     try {

+ 3 - 1
src/server/trpc.ts

@@ -4,8 +4,10 @@ import { typeToFlattenedError, ZodError } from 'zod';
 import { type Context } from './context';
 import { type Context } from './context';
 
 
 /**
 /**
+ * Convert ZodError to a record
  *
  *
- * @param errors
+ * @param {typeToFlattenedError<string>} errors - errors
+ * @returns {Record<string, string>} record
  */
  */
 export function zodErrorsToRecord(errors: typeToFlattenedError<string>) {
 export function zodErrorsToRecord(errors: typeToFlattenedError<string>) {
   const record: Record<string, string> = {};
   const record: Record<string, string> = {};