refactor(source): define more types (#149)

* define more types

* lint fixes

* update snapshot and reduce coverage

* revert role change, since it incompatible with directus
This commit is contained in:
Ulf Gebhardt 2025-02-22 17:09:38 +01:00 committed by GitHub
parent 63e864ff81
commit 12fd624780
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 58 additions and 60 deletions

View File

@ -1,5 +1,4 @@
/* eslint-disable @typescript-eslint/consistent-type-definitions */ interface ContentProps {
type ContentProps = {
children?: React.ReactNode children?: React.ReactNode
} }

View File

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useContext, createContext } from 'react' import { useContext, createContext } from 'react'
import { BrowserRouter as Router, useLocation } from 'react-router-dom' import { BrowserRouter as Router, useLocation } from 'react-router-dom'
@ -19,8 +18,7 @@ import { AppStateProvider } from './hooks/useAppState'
// Helper context to determine if the ContextWrapper is already present. // Helper context to determine if the ContextWrapper is already present.
const ContextCheckContext = createContext(false) const ContextCheckContext = createContext(false)
// eslint-disable-next-line react/prop-types export const ContextWrapper = ({ children }: { children: React.ReactNode }) => {
export const ContextWrapper = ({ children }) => {
const isWrapped = useContext(ContextCheckContext) const isWrapped = useContext(ContextCheckContext)
// Check if we are already inside a Router // Check if we are already inside a Router

View File

@ -1,4 +1,3 @@
/* eslint-disable react/prop-types */
/* eslint-disable @typescript-eslint/no-empty-function */ /* eslint-disable @typescript-eslint/no-empty-function */
import { useCallback, useState, createContext, useContext } from 'react' import { useCallback, useState, createContext, useContext } from 'react'
@ -22,10 +21,15 @@ function useQuestsManager(initialOpen: boolean): {
return { open, setQuestsOpen } return { open, setQuestsOpen }
} }
export const QuestsProvider: React.FunctionComponent<{ interface QuestProviderProps {
initialOpen: boolean initialOpen: boolean
children?: React.ReactNode children?: React.ReactNode
}> = ({ initialOpen, children }) => ( }
export const QuestsProvider: React.FunctionComponent<QuestProviderProps> = ({
initialOpen,
children,
}: QuestProviderProps) => (
<QuestContext.Provider value={useQuestsManager(initialOpen)}>{children}</QuestContext.Provider> <QuestContext.Provider value={useQuestsManager(initialOpen)}>{children}</QuestContext.Provider>
) )

View File

@ -1,9 +1,7 @@
/* eslint-disable @typescript-eslint/consistent-type-definitions */
/* eslint-disable @typescript-eslint/restrict-template-expressions */
import InformationCircleIcon from '@heroicons/react/24/outline/InformationCircleIcon' import InformationCircleIcon from '@heroicons/react/24/outline/InformationCircleIcon'
import { useState } from 'react' import { useState } from 'react'
type SelectBoxProps = { interface SelectBoxProps {
labelTitle?: string labelTitle?: string
labelStyle?: string labelStyle?: string
type?: string type?: string
@ -40,9 +38,9 @@ export function SelectBox(props: SelectBoxProps) {
} }
return ( return (
<div className={`tw-inline-block ${containerStyle}`}> <div className={`tw-inline-block ${containerStyle ?? ''}`}>
{labelTitle ? ( {labelTitle ? (
<label className={`tw-label ${labelStyle}`}> <label className={`tw-label ${labelStyle ?? ''}`}>
<div className='tw-label-text'> <div className='tw-label-text'>
{labelTitle} {labelTitle}
{labelDescription && ( {labelDescription && (

View File

@ -1,12 +1,8 @@
/* eslint-disable @typescript-eslint/consistent-type-definitions */
/* eslint-disable @typescript-eslint/consistent-indexed-object-style */
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { useTags } from '#components/Map/hooks/useTags' import { useTags } from '#components/Map/hooks/useTags'
type TextAreaProps = { interface TextAreaProps {
labelTitle?: string labelTitle?: string
labelStyle?: string labelStyle?: string
containerStyle?: string containerStyle?: string
@ -18,9 +14,7 @@ type TextAreaProps = {
updateFormValue?: (value: string) => void updateFormValue?: (value: string) => void
} }
interface KeyValue { type KeyValue = Record<string, string>
[key: string]: string
}
/** /**
* @category Input * @category Input
@ -60,10 +54,12 @@ export function TextAreaInput({
} }
return ( return (
<div className={`tw-form-control tw-w-full ${containerStyle || ''}`}> <div className={`tw-form-control tw-w-full ${containerStyle ?? ''}`}>
{labelTitle ? ( {labelTitle ? (
<label className='tw-label'> <label className='tw-label'>
<span className={`tw-label-text tw-text-base-content ${labelStyle}`}>{labelTitle}</span> <span className={`tw-label-text tw-text-base-content ${labelStyle ?? ''}`}>
{labelTitle}
</span>
</label> </label>
) : null} ) : null}
<textarea <textarea
@ -71,8 +67,8 @@ export function TextAreaInput({
ref={ref} ref={ref}
value={inputValue} value={inputValue}
name={dataField} name={dataField}
className={`tw-textarea tw-textarea-bordered tw-w-full tw-leading-5 ${inputStyle || ''}`} className={`tw-textarea tw-textarea-bordered tw-w-full tw-leading-5 ${inputStyle ?? ''}`}
placeholder={placeholder || ''} placeholder={placeholder ?? ''}
onChange={handleChange} onChange={handleChange}
></textarea> ></textarea>
</div> </div>

View File

@ -1,9 +1,6 @@
/* eslint-disable @typescript-eslint/consistent-type-definitions */
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
type InputTextProps = { interface InputTextProps {
labelTitle?: string labelTitle?: string
labelStyle?: string labelStyle?: string
type?: string type?: string
@ -35,10 +32,10 @@ export function TextInput({
required = true, required = true,
updateFormValue, updateFormValue,
}: InputTextProps) { }: InputTextProps) {
const [inputValue, setInputValue] = useState<string>(defaultValue || '') const [inputValue, setInputValue] = useState<string>(defaultValue ?? '')
useEffect(() => { useEffect(() => {
setInputValue(defaultValue || '') setInputValue(defaultValue ?? '')
}, [defaultValue]) }, [defaultValue])
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
@ -50,22 +47,24 @@ export function TextInput({
} }
return ( return (
<div className={`tw-form-control ${containerStyle}`}> <div className={`tw-form-control ${containerStyle ?? ''}`}>
{labelTitle ? ( {labelTitle ? (
<label className='tw-label'> <label className='tw-label'>
<span className={`tw-label-text tw-text-base-content ${labelStyle}`}>{labelTitle}</span> <span className={`tw-label-text tw-text-base-content ${labelStyle ?? ''}`}>
{labelTitle}
</span>
</label> </label>
) : null} ) : null}
<input <input
required={required} required={required}
pattern={pattern} pattern={pattern}
type={type || 'text'} type={type ?? 'text'}
name={dataField} name={dataField}
value={inputValue} value={inputValue}
placeholder={placeholder || ''} placeholder={placeholder ?? ''}
autoComplete={autocomplete} autoComplete={autocomplete}
onChange={handleChange} onChange={handleChange}
className={`tw-input tw-input-bordered tw-w-full ${inputStyle || ''}`} className={`tw-input tw-input-bordered tw-w-full ${inputStyle ?? ''}`}
/> />
</div> </div>
) )

View File

@ -2,13 +2,13 @@
exports[`<TextInput /> > labelTitle > sets label 1`] = ` exports[`<TextInput /> > labelTitle > sets label 1`] = `
<div <div
class="tw-form-control undefined" class="tw-form-control "
> >
<label <label
class="tw-label" class="tw-label"
> >
<span <span
class="tw-label-text tw-text-base-content undefined" class="tw-label-text tw-text-base-content "
> >
My Title My Title
</span> </span>
@ -25,7 +25,7 @@ exports[`<TextInput /> > labelTitle > sets label 1`] = `
exports[`<TextInput /> > renders properly 1`] = ` exports[`<TextInput /> > renders properly 1`] = `
<div <div
class="tw-form-control undefined" class="tw-form-control "
> >
<input <input
class="tw-input tw-input-bordered tw-w-full " class="tw-input tw-input-bordered tw-w-full "

View File

@ -1,9 +1,8 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { useEffect } from 'react' import { useEffect } from 'react'
import { useTimeout } from './useTimeout' import { useTimeout } from './useTimeout'
export const useDebounce = (callback, delay, deps) => { export const useDebounce = (callback: () => void, delay: number, deps: string[]) => {
const { reset, clear } = useTimeout(callback, delay) const { reset, clear } = useTimeout(callback, delay)
useEffect(reset, [...deps, reset]) useEffect(reset, [...deps, reset])

View File

@ -1,5 +1,3 @@
/* eslint-disable react/prop-types */
/* eslint-disable @typescript-eslint/no-empty-function */
import { useCallback, useReducer, createContext, useContext } from 'react' import { useCallback, useReducer, createContext, useContext } from 'react'
import type { LayerProps } from '#types/LayerProps' import type { LayerProps } from '#types/LayerProps'
@ -13,6 +11,7 @@ type UseItemManagerResult = ReturnType<typeof useLayerManager>
const LayerContext = createContext<UseItemManagerResult>({ const LayerContext = createContext<UseItemManagerResult>({
layers: [], layers: [],
// eslint-disable-next-line @typescript-eslint/no-empty-function
addLayer: () => {}, addLayer: () => {},
}) })
@ -46,7 +45,7 @@ function useLayerManager(initialLayers: LayerProps[]): {
export const LayersProvider: React.FunctionComponent<{ export const LayersProvider: React.FunctionComponent<{
initialLayers: LayerProps[] initialLayers: LayerProps[]
children?: React.ReactNode children?: React.ReactNode
}> = ({ initialLayers, children }) => ( }> = ({ initialLayers, children }: { initialLayers: LayerProps[]; children?: React.ReactNode }) => (
<LayerContext.Provider value={useLayerManager(initialLayers)}>{children}</LayerContext.Provider> <LayerContext.Provider value={useLayerManager(initialLayers)}>{children}</LayerContext.Provider>
) )

View File

@ -1,11 +1,8 @@
/* eslint-disable react/prop-types */
/* eslint-disable @typescript-eslint/no-misused-promises */ /* eslint-disable @typescript-eslint/no-misused-promises */
/* eslint-disable @typescript-eslint/no-empty-function */ /* eslint-disable @typescript-eslint/no-empty-function */
/* eslint-disable @typescript-eslint/prefer-optional-chain */ /* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { useCallback, useReducer, createContext, useContext, useState } from 'react' import { useCallback, useReducer, createContext, useContext, useState } from 'react'
import { useAuth } from '#components/Auth/useAuth' import { useAuth } from '#components/Auth/useAuth'
@ -15,6 +12,7 @@ import type { ItemsApi } from '#types/ItemsApi'
import type { LayerProps } from '#types/LayerProps' import type { LayerProps } from '#types/LayerProps'
import type { Permission } from '#types/Permission' import type { Permission } from '#types/Permission'
import type { PermissionAction } from '#types/PermissionAction' import type { PermissionAction } from '#types/PermissionAction'
import type { PermissionCondition } from '#types/PermissionCondition'
type ActionType = { type: 'ADD'; permission: Permission } | { type: 'REMOVE'; id: string } type ActionType = { type: 'ADD'; permission: Permission } | { type: 'REMOVE'; id: string }
@ -30,7 +28,7 @@ const PermissionContext = createContext<UsePermissionManagerResult>({
function usePermissionsManager(initialPermissions: Permission[]): { function usePermissionsManager(initialPermissions: Permission[]): {
permissions: Permission[] permissions: Permission[]
setPermissionApi: (api: ItemsApi<any>) => void setPermissionApi: (api: ItemsApi<Permission>) => void
setPermissionData: (data: Permission[]) => void setPermissionData: (data: Permission[]) => void
setAdminRole: (adminRole: string) => void setAdminRole: (adminRole: string) => void
hasUserPermission: ( hasUserPermission: (
@ -76,7 +74,7 @@ function usePermissionsManager(initialPermissions: Permission[]): {
const hasUserPermission = useCallback( const hasUserPermission = useCallback(
(collectionName: string, action: PermissionAction, item?: Item, layer?: LayerProps) => { (collectionName: string, action: PermissionAction, item?: Item, layer?: LayerProps) => {
const evaluateCondition = (condition: any) => { const evaluateCondition = (condition: PermissionCondition) => {
if (condition.user_created?._eq === '$CURRENT_USER') { if (condition.user_created?._eq === '$CURRENT_USER') {
return item?.user_created?.id === user?.id return item?.user_created?.id === user?.id
} }
@ -86,27 +84,29 @@ function usePermissionsManager(initialPermissions: Permission[]): {
return false return false
} }
const evaluatePermissions = (permissionConditions: any) => { const evaluatePermissions = (permissionConditions: Permission['permissions']) => {
if (!permissionConditions || !permissionConditions._and) { if (!permissionConditions?._and) {
return true return true
} }
return permissionConditions._and.every((andCondition: any) => return permissionConditions._and.every((andCondition: PermissionCondition) =>
andCondition._or (andCondition as any)._or
? andCondition._or.some((orCondition: any) => evaluateCondition(orCondition)) ? (andCondition as any)._or.some((orCondition: PermissionCondition) =>
evaluateCondition(orCondition),
)
: evaluateCondition(andCondition), : evaluateCondition(andCondition),
) )
} }
if (collectionName === 'items' && action === 'create' && layer?.public_edit_items) return true if (collectionName === 'items' && action === 'create' && layer?.public_edit_items) return true
// Bedingung für leere Berechtigungen nur, wenn NICHT item und create // Bedingung für leere Berechtigungen nur, wenn NICHT item und create
if (permissions.length === 0) return true if (permissions.length === 0) return true
else if (user && user.role.id === adminRole) return true else if (user && user.role?.id === adminRole) return true
else { else {
return permissions.some( return permissions.some(
(p) => (p) =>
p.action === action && p.action === action &&
p.collection === collectionName && p.collection === collectionName &&
((p.policy?.name === user?.role.name && ((p.policy?.name === user?.role?.name &&
(!item || evaluatePermissions(p.permissions))) || (!item || evaluatePermissions(p.permissions))) ||
(p.policy?.name === '$t:public_label' && (p.policy?.name === '$t:public_label' &&
(layer?.public_edit_items || item?.layer?.public_edit_items) && (layer?.public_edit_items || item?.layer?.public_edit_items) &&
@ -123,7 +123,13 @@ function usePermissionsManager(initialPermissions: Permission[]): {
export const PermissionsProvider: React.FunctionComponent<{ export const PermissionsProvider: React.FunctionComponent<{
initialPermissions: Permission[] initialPermissions: Permission[]
children?: React.ReactNode children?: React.ReactNode
}> = ({ initialPermissions, children }) => ( }> = ({
initialPermissions,
children,
}: {
initialPermissions: Permission[]
children?: React.ReactNode
}) => (
<PermissionContext.Provider value={usePermissionsManager(initialPermissions)}> <PermissionContext.Provider value={usePermissionsManager(initialPermissions)}>
{children} {children}
</PermissionContext.Provider> </PermissionContext.Provider>

View File

@ -14,8 +14,8 @@ export default defineConfig({
exclude: [...configDefaults.exclude], exclude: [...configDefaults.exclude],
thresholds: { thresholds: {
lines: 0, lines: 0,
functions: 65, functions: 61,
branches: 66, branches: 62,
statements: 0, statements: 0,
}, },
}, },