diff --git a/apps/example/src/components/auth/Avatar.tsx b/apps/example/src/components/auth/Avatar.tsx
index b28a6754f..492b350ee 100644
--- a/apps/example/src/components/auth/Avatar.tsx
+++ b/apps/example/src/components/auth/Avatar.tsx
@@ -4,10 +4,9 @@
*/
import React from "react"
-import PropTypes from "prop-types"
import { Stack } from "@cloudoperators/juno-ui-components"
-const avatarCss = `
+const avatarStyles = `
h-8
w-8
bg-theme-background-lvl-2
@@ -15,7 +14,12 @@ rounded-full
bg-cover
`
-const Avatar = ({ userName, url }: any) => {
+interface AvatarProps {
+ userName?: string
+ url?: string
+}
+
+const Avatar: React.FC = ({ userName, url }) => {
return (
{url && (
@@ -24,7 +28,7 @@ const Avatar = ({ userName, url }: any) => {
background: `url(${url}) no-repeat`,
backgroundSize: `cover`,
}}
- className={avatarCss}
+ className={avatarStyles}
/>
)}
{userName && {userName}}
@@ -32,9 +36,4 @@ const Avatar = ({ userName, url }: any) => {
)
}
-Avatar.propTypes = {
- userName: PropTypes.string,
- url: PropTypes.string,
-}
-
export default Avatar
diff --git a/apps/example/src/components/auth/HeaderUser.tsx b/apps/example/src/components/auth/HeaderUser.tsx
index 8345020d4..c27c4eb6c 100644
--- a/apps/example/src/components/auth/HeaderUser.tsx
+++ b/apps/example/src/components/auth/HeaderUser.tsx
@@ -1,19 +1,20 @@
-/* eslint-disable @typescript-eslint/no-unsafe-call */
-/* eslint-disable @typescript-eslint/no-unsafe-return */
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/*
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
*/
import React from "react"
-import PropTypes from "prop-types"
import { Stack, Button } from "@cloudoperators/juno-ui-components"
+
import Avatar from "./Avatar"
import { useAuthLoggedIn, useAuthData } from "../StoreProvider"
-const HeaderUser = ({ login, logout }: any) => {
+interface HeaderUserProps {
+ login: () => void
+ logout: () => void
+}
+
+const HeaderUser: React.FC = ({ login, logout }) => {
const loggedIn = useAuthLoggedIn()
const authData = useAuthData()
@@ -22,23 +23,15 @@ const HeaderUser = ({ login, logout }: any) => {
{loggedIn ? (
<>
- {/* @ts-ignore */}
-
)
}
-HeaderUser.propTypes = {
- login: PropTypes.func,
- logout: PropTypes.func,
-}
-
export default HeaderUser
diff --git a/apps/example/src/components/peaks/Peaks.tsx b/apps/example/src/components/peaks/Peaks.tsx
index b32a199c7..932f45914 100644
--- a/apps/example/src/components/peaks/Peaks.tsx
+++ b/apps/example/src/components/peaks/Peaks.tsx
@@ -5,26 +5,48 @@
import React from "react"
import { useQuery } from "@tanstack/react-query"
-import PeaksList from "./PeaksList"
import { Spinner, Message } from "@cloudoperators/juno-ui-components"
+
import { useGlobalsQueryClientFnReady } from "../StoreProvider"
+import PeaksList from "./PeaksList"
+
+interface CustomError {
+ name: string
+ message: string
+ statusCode?: number
+}
+
+export interface Peak {
+ id: number
+ name: string
+ height: number
+ mainrange: string
+ region: string
+ countries: string
+ url: string
+}
-const Peaks = () => {
+const Peaks: React.FC = () => {
const queryClientFnReady = useGlobalsQueryClientFnReady()
- const { isLoading, isError, data, error } = useQuery({
- queryKey: [`peaks`],
+ const {
+ isLoading,
+ isError,
+ data = [],
+ error,
+ } = useQuery({
+ queryKey: ["peaks"],
enabled: !!queryClientFnReady,
})
return (
<>
{isError && (
- {`${error.statusCode ? `${error.statusCode}, ` : ""}${error?.message}`}
+ {`${error?.statusCode ? `${error.statusCode}, ` : ""}${error?.message}`}
)}
{/* Loading indicator for page content */}
{isLoading && }
-
+
>
)
}
diff --git a/apps/example/src/components/peaks/PeaksEdit.tsx b/apps/example/src/components/peaks/PeaksEdit.tsx
index c91c955f9..a5f7ceb24 100644
--- a/apps/example/src/components/peaks/PeaksEdit.tsx
+++ b/apps/example/src/components/peaks/PeaksEdit.tsx
@@ -1,44 +1,83 @@
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
-/* eslint-disable @typescript-eslint/no-floating-promises */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/*
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
*/
-import React, { useState, useEffect } from "react"
-import PropTypes from "prop-types"
+import React, { useState, useEffect, ChangeEvent } from "react"
import { Button, Form, PanelBody, PanelFooter, FormRow, TextInput } from "@cloudoperators/juno-ui-components"
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
+import { useQuery, useMutation, useQueryClient, QueryObserverResult } from "@tanstack/react-query"
+
import HintLoading from "../shared/HintLoading"
import { useGlobalsQueryClientFnReady } from "../StoreProvider"
+import { Peak } from "./Peaks"
+
+interface FormState {
+ name?: string
+ height?: string
+ mainrange?: string
+ region?: string
+ countries?: string
+}
+
+interface PeaksEditProps {
+ peakId: string
+ closeCallback: () => void
+}
+
+const toFormState = (peak: Peak): FormState => ({
+ name: peak.name,
+ height: peak.height.toString(),
+ mainrange: peak.mainrange,
+ region: peak.region,
+ countries: peak.countries,
+})
-const PeaksEdit = ({ peakId, closeCallback }: any) => {
+const PeaksEdit: React.FC = ({ peakId, closeCallback }) => {
const queryClient = useQueryClient()
const queryClientFnReady = useGlobalsQueryClientFnReady()
- const [formState, setFormState] = useState({})
+ const [formState, setFormState] = useState({})
- const peakFeach = useQuery({
- queryKey: [`peaks`, peakId],
+ const fetchPeakData = async (): Promise => {
+ const response: Response = await fetch(`/api/peaks/${peakId}`)
+ if (!response.ok) {
+ throw new Error("Network response was not ok")
+ }
+ return response.json() as Promise
+ }
+
+ const peakFetch: QueryObserverResult = useQuery({
+ queryKey: ["peaks", peakId],
enabled: !!queryClientFnReady,
+ queryFn: fetchPeakData,
})
+ const updatePeakData = async (data: { id: string; formState: FormState }): Promise => {
+ const response: Response = await fetch(`/api/peaks/${data.id}`, {
+ method: "PUT",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(data.formState),
+ })
+ if (!response.ok) {
+ throw new Error("Network response was not ok")
+ }
+ return response.json() as Promise
+ }
+
const peakMutation = useMutation({
mutationKey: ["peakEdit"],
+ mutationFn: updatePeakData,
})
useEffect(() => {
- if (peakFeach.isSuccess) {
- //@ts-ignore
- setFormState(peakFeach.data)
+ if (peakFetch.isSuccess && peakFetch.data) {
+ setFormState(toFormState(peakFetch.data))
}
- }, [peakFeach.isSuccess])
+ }, [peakFetch.isSuccess, peakFetch.data])
const onSubmit = () => {
- // TODO form validation
peakMutation.mutate(
- //@ts-ignore
{
id: peakId,
formState: formState,
@@ -46,86 +85,67 @@ const PeaksEdit = ({ peakId, closeCallback }: any) => {
{
onSuccess: () => {
closeCallback()
- // refetch peaks
- //@ts-ignore
- queryClient.invalidateQueries("peaks")
+ void queryClient.invalidateQueries(["peaks"])
},
- onError: () => {
- // TODO display error
+ onError: (error) => {
+ console.error("Error updating peak:", error)
},
}
)
}
- const onAttrChanged = (key: any, value: any) => {
+ const onAttrChanged = (key: keyof FormState, value: string) => {
setFormState({ ...formState, [key]: value })
}
return (
- {/* @ts-ignore */}
- {/* @ts-ignore */}
)
}
>
- {peakFeach.isLoading ? (
+ {peakFetch.isLoading ? (
) : (
@@ -134,9 +154,4 @@ const PeaksEdit = ({ peakId, closeCallback }: any) => {
)
}
-PeaksEdit.propTypes = {
- peakId: PropTypes.string,
- closeCallback: PropTypes.func,
-}
-
export default PeaksEdit
diff --git a/apps/example/src/components/peaks/PeaksList.tsx b/apps/example/src/components/peaks/PeaksList.tsx
index 657708c12..c19f71b5b 100644
--- a/apps/example/src/components/peaks/PeaksList.tsx
+++ b/apps/example/src/components/peaks/PeaksList.tsx
@@ -1,14 +1,14 @@
-/* eslint-disable @typescript-eslint/no-unsafe-return */
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
+/* eslint-disable no-unused-vars */
+/* eslint-disable @typescript-eslint/no-unsafe-assignment*/
/* eslint-disable @typescript-eslint/no-unsafe-call */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
+/* eslint-disable @typescript-eslint/no-unsafe-member-access */
+
/*
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
*/
-import React, { useMemo } from "react"
-import PropTypes from "prop-types"
+import React, { useMemo, MutableRefObject } from "react"
import {
Button,
ContentAreaToolbar,
@@ -18,40 +18,50 @@ import {
DataGridCell,
useEndlessScrollList,
} from "@cloudoperators/juno-ui-components"
+
+import { Peak } from "./Peaks"
import PeaksListItem from "./PeaksListItem"
import HintNotFound from "../shared/HintNotFound"
import { useGlobalsActions } from "../StoreProvider"
+interface CustomError {
+ name: string
+ message: string
+ statusCode?: number
+}
+
+interface PeaksListProps {
+ peaks: Peak[]
+ isLoading: boolean
+ isError: boolean
+ error?: CustomError
+}
+
const LIST_COLUMNS = 6
-const PeaksList = ({ peaks }: any) => {
- //@ts-ignore
+const PeaksList: React.FC = ({ peaks, isLoading, isError, error }) => {
const { setCurrentPanel } = useGlobalsActions()
- const items = useMemo(() => {
- if (!peaks) return []
- return peaks
- }, [peaks])
+ const items = useMemo(() => peaks, [peaks])
+
+ const refFunction = (ref: MutableRefObject): React.ReactElement => (
+
+
+
+
+
+ )
- const { scrollListItems, iterator } = useEndlessScrollList(items, {
+ const { scrollListItems = [], iterator } = useEndlessScrollList(items, {
loadingObject: (
- //@ts-ignore
- {/* @ts-ignore */}
Loading ...
),
- refFunction: (ref: any) => (
- //@ts-ignore
-
- {/* @ts-ignore */}
-
-
-
-
- ),
+ //@ts-ignore
+ refFunction,
})
const handleNewPeakClick = () => {
@@ -61,37 +71,26 @@ const PeaksList = ({ peaks }: any) => {
return (
<>
- {/* @ts-ignore */}
- {/* @ts-ignore */}
- {/* @ts-ignore */}
- {/* @ts-ignore */}
Name
- {/* @ts-ignore */}
Height
- {/* @ts-ignore */}
Main Range
- {/* @ts-ignore */}
Region
- {/* @ts-ignore */}
Country
- {/* @ts-ignore */}
Options
-
- {scrollListItems?.length > 0 ? (
+ {scrollListItems.length > 0 ? (
<>
- {iterator.map((peak: any, index: any) => (
+ {/* @ts-ignore */}
+ {iterator.map((peak: Peak, index: number) => (
))}
>
) : (
- //@ts-ignore
- {/* @ts-ignore */}
@@ -102,8 +101,4 @@ const PeaksList = ({ peaks }: any) => {
)
}
-PeaksList.propTypes = {
- peaks: PropTypes.array,
-}
-
export default PeaksList
diff --git a/apps/example/src/components/peaks/PeaksListItem.tsx b/apps/example/src/components/peaks/PeaksListItem.tsx
index 736dbe42e..901b3be71 100644
--- a/apps/example/src/components/peaks/PeaksListItem.tsx
+++ b/apps/example/src/components/peaks/PeaksListItem.tsx
@@ -1,25 +1,34 @@
-/* eslint-disable @typescript-eslint/no-floating-promises */
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
/*
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
*/
import React from "react"
-import PropTypes from "prop-types"
import { DataGridCell, DataGridRow, Icon, Stack } from "@cloudoperators/juno-ui-components"
import { useMutation, useQueryClient } from "@tanstack/react-query"
+
+import { Peak } from "./Peaks"
import { useGlobalsActions } from "../StoreProvider"
-const PeaksListItem = ({ peak }: any) => {
+interface PeaksListItemProps {
+ peak: Peak
+}
+
+const PeaksListItem: React.FC = ({ peak }) => {
const queryClient = useQueryClient()
- //@ts-ignore
const { setCurrentPanel } = useGlobalsActions()
const { mutate } = useMutation({
mutationKey: ["peakDelete"],
+ mutationFn: async ({ id }: { id: number }) => {
+ const response = await fetch(`/api/peaks/${id}`, {
+ method: "DELETE",
+ })
+ if (!response.ok) {
+ throw new Error("Deletion failed")
+ }
+ return id
+ },
})
const handleEditPeakClick = () => {
@@ -28,56 +37,36 @@ const PeaksListItem = ({ peak }: any) => {
const handleDeletePeakClick = () => {
mutate(
- //@ts-ignore
- {
- id: peak.id,
- },
+ { id: peak.id },
{
onSuccess: () => {
- // refetch peaks
- //@ts-ignore
- queryClient.invalidateQueries("peaks")
+ void queryClient.invalidateQueries(["peaks"])
},
- onError: () => {
- // TODO display error
+ onError: (error) => {
+ console.error("Error deleting peak:", error)
},
}
)
}
return (
- //@ts-ignore
- {/* @ts-ignore */}
{peak.name}
- {/* @ts-ignore */}
- {peak.height}
- {/* @ts-ignore */}
+ {peak.height.toString()}
{peak.mainrange}
- {/* @ts-ignore */}
{peak.region}
- {/* @ts-ignore */}
{peak.countries}
- {/* @ts-ignore */}
- {/* Use to align and space elements: */}
- {/* @ts-ignore */}
- {/* @ts-ignore */}
- {/* @ts-ignore */}
- {peak?.url && }
+ {peak.url && }
)
}
-PeaksListItem.propTypes = {
- peak: PropTypes.object,
-}
-
export default PeaksListItem
diff --git a/apps/example/src/components/peaks/PeaksNew.tsx b/apps/example/src/components/peaks/PeaksNew.tsx
index 9bb20496d..5af29ff76 100644
--- a/apps/example/src/components/peaks/PeaksNew.tsx
+++ b/apps/example/src/components/peaks/PeaksNew.tsx
@@ -1,50 +1,77 @@
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-floating-promises */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
+/* eslint-disable no-unused-vars */
+/* eslint-disable @typescript-eslint/no-unsafe-call*/
+
/*
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
*/
-import React, { useState } from "react"
-import PropTypes from "prop-types"
+import React, { useState, ChangeEvent } from "react"
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { useActions } from "@cloudoperators/juno-messages-provider"
import { PanelBody, PanelFooter, Button, FormRow, TextInput } from "@cloudoperators/juno-ui-components"
-const PeaksNew = ({ closeCallback }: any) => {
+interface FormState {
+ name?: string
+ height?: string
+ range?: string
+ region?: string
+ country?: string
+ url?: string
+}
+
+interface PeaksNewProps {
+ closeCallback: () => void
+}
+
+interface AddMessage {
+ variant: "success" | "error" | "info" | "warning"
+ text: string
+}
+
+const PeaksNew: React.FC = ({ closeCallback }) => {
const queryClient = useQueryClient()
- const [formState, setFormState] = useState({})
- const { addMessage } = useActions()
+ const [formState, setFormState] = useState({})
+ // To do: Fix type in package
+ const { addMessage } = useActions() as { addMessage: (message: AddMessage) => void }
- const { mutate } = useMutation({
+ const { mutateAsync } = useMutation({
mutationKey: ["peakAdd"],
- })
-
- const onSubmit = () => {
- mutate(
- //@ts-ignore
- { formState: formState },
- {
- onSuccess: (/*data, variables, context*/) => {
- addMessage({
- variant: "success",
- text: `Successfully added Peak`,
- })
- closeCallback()
- // refetch peaks
- //@ts-ignore
- queryClient.invalidateQueries("peaks")
- },
- onError: (/*error, variables, context*/) => {
- // TODO display error
+ mutationFn: async (data: { formState: FormState }) => {
+ const response = await fetch("/api/peaks", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
},
+ body: JSON.stringify(data.formState),
+ })
+ if (!response.ok) {
+ throw new Error("Network response was not ok")
}
- )
+ return response.json()
+ },
+ })
+
+ const onSubmit = async () => {
+ try {
+ await mutateAsync({ formState })
+ addMessage({
+ variant: "success",
+ text: `Successfully added Peak`,
+ })
+ closeCallback()
+ await queryClient.invalidateQueries(["peaks"])
+ } catch (error) {
+ // TODO display error
+ console.error("Error adding peak:", error)
+ }
}
- const onAttrChanged = (key: any, value: any) => {
+ const handleOnSubmit = () => {
+ void onSubmit()
+ }
+
+ const onAttrChanged = (key: keyof FormState, value: string) => {
setFormState({ ...formState, [key]: value })
}
@@ -52,43 +79,51 @@ const PeaksNew = ({ closeCallback }: any) => {
- {/* @ts-ignore */}
- {/* @ts-ignore */}
-
+
}
>
- {/* @ts-ignore */}
- onAttrChanged("name", e.target.value)} />
+ ) => onAttrChanged("name", e.target.value)}
+ />
- {/* @ts-ignore */}
- onAttrChanged("height", e.target.value)} />
+ ) => onAttrChanged("height", e.target.value)}
+ />
- {/* @ts-ignore */}
- onAttrChanged("range", e.target.value)} />
+ ) => onAttrChanged("range", e.target.value)}
+ />
- {/* @ts-ignore */}
- onAttrChanged("region", e.target.value)} />
+ ) => onAttrChanged("region", e.target.value)}
+ />
- {/* @ts-ignore */}
- onAttrChanged("country", e.target.value)} />
+ ) => onAttrChanged("country", e.target.value)}
+ />
- {/* @ts-ignore */}
- onAttrChanged("url", e.target.value)} />
+ ) => onAttrChanged("url", e.target.value)}
+ />
)
}
-PeaksNew.propTypes = {
- closeCallback: PropTypes.func,
-}
-
export default PeaksNew
diff --git a/apps/example/src/components/shared/HintLoading.tsx b/apps/example/src/components/shared/HintLoading.tsx
index 28c0cd26e..d52724db0 100644
--- a/apps/example/src/components/shared/HintLoading.tsx
+++ b/apps/example/src/components/shared/HintLoading.tsx
@@ -4,19 +4,19 @@
*/
import React from "react"
-import PropTypes from "prop-types"
import { Stack, Spinner } from "@cloudoperators/juno-ui-components"
-const HintLoading = ({ text }: any) => {
+interface HintLoadingProps {
+ text?: string
+}
+
+const HintLoading: React.FC = ({ text }) => {
return (
- {text ? {text} : Loading...}
+ {text ? text : "Loading..."}
)
}
-HintLoading.propTypes = {
- text: PropTypes.string,
-}
export default HintLoading
diff --git a/apps/example/src/components/shared/HintNotFound.tsx b/apps/example/src/components/shared/HintNotFound.tsx
index 4b1a95326..2e374745a 100644
--- a/apps/example/src/components/shared/HintNotFound.tsx
+++ b/apps/example/src/components/shared/HintNotFound.tsx
@@ -4,10 +4,13 @@
*/
import React from "react"
-import PropTypes from "prop-types"
import { Stack } from "@cloudoperators/juno-ui-components"
-const HintNotFound = ({ text }: any) => {
+interface HintNotFoundProps {
+ text?: string
+}
+
+const HintNotFound: React.FC = ({ text }) => {
return (
{text || "No items found"}
@@ -15,8 +18,4 @@ const HintNotFound = ({ text }: any) => {
)
}
-HintNotFound.propTypes = {
- text: PropTypes.string,
-}
-
export default HintNotFound
diff --git a/apps/example/src/hooks/useQueryClientFn.ts b/apps/example/src/hooks/useQueryClientFn.ts
index a2b8baeaf..1bccda986 100644
--- a/apps/example/src/hooks/useQueryClientFn.ts
+++ b/apps/example/src/hooks/useQueryClientFn.ts
@@ -1,10 +1,8 @@
-/* eslint-disable @typescript-eslint/restrict-template-expressions */
-/* eslint-disable @typescript-eslint/no-base-to-string */
+/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-return */
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
+
/*
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
@@ -12,20 +10,20 @@
import { useEffect } from "react"
import { useQueryClient } from "@tanstack/react-query"
+
import { useGlobalsEndpoint, useGlobalsActions } from "../components/StoreProvider"
class HTTPError extends Error {
- statusCode: any
- constructor(code: any, message: any) {
- super(message || code)
+ statusCode: number
+ constructor(code: number, message: string) {
+ super(message || `${code}`)
this.name = "HTTPError"
this.statusCode = code
}
}
-const encodeUrlParamsFromObject = (options: any) => {
- // @ts-expect-error TS(2365): Operator '<=' cannot be applied to types 'string[]... Remove this comment to see the full error message
- if (!options || Object.keys(options) <= 0) return ""
+const encodeUrlParamsFromObject = (options: Record) => {
+ if (!options || Object.keys(options).length <= 0) return ""
const encodedOptions = Object.keys(options)
.map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(options[k])}`)
.join("&")
@@ -33,13 +31,12 @@ const encodeUrlParamsFromObject = (options: any) => {
}
// Check response status
-const checkStatus = (response: any) => {
+const checkStatus = (response: Response) => {
if (response.status < 400) {
return response
} else {
- return response.text().then((message: any) => {
+ return response.text().then((message) => {
const error = new HTTPError(response.status, message || response.statusText)
- error.statusCode = response.status
return Promise.reject(error)
})
}
@@ -61,10 +58,10 @@ const useQueryClientFn = () => {
console.debug("useQueryClientFn::: setting defaults: ", endpoint)
queryClient.setQueryDefaults(["peaks"], {
- queryFn: ({ queryKey }: any) => {
- const [_key, id, params] = queryKey
- const query = encodeUrlParamsFromObject(params)
- return fetch(`${endpoint}/peaks${id ? "/" + id : ""}${query ? "" + query : ""}`, {
+ queryFn: ({ queryKey }) => {
+ const [_key, id, params] = queryKey as [string, string?, Record?]
+ const query = encodeUrlParamsFromObject(params || {})
+ return fetch(`${endpoint}/peaks${id ? `/${id}` : ""}${query}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
@@ -73,8 +70,8 @@ const useQueryClientFn = () => {
})
.then(checkStatus)
.then((response) => {
- // sort peaks by name
- return response.json().then((data: any) => {
+ // sort peaks by name
+ return response.json().then((data) => {
// check if data is an array to sort (peaks vs peak/id)
if (Array.isArray(data)) {
return data.sort((a, b) => {
@@ -88,8 +85,7 @@ const useQueryClientFn = () => {
})
queryClient.setMutationDefaults(["peakAdd"], {
- mutationFn: ({ formState }: any) => {
- // Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
+ mutationFn: ({ formState }) => {
const sendBody = JSON.stringify(formState)
return fetch(`${endpoint}/peaks`, {
method: "POST",
@@ -107,8 +103,7 @@ const useQueryClientFn = () => {
})
queryClient.setMutationDefaults(["peakEdit"], {
- mutationFn: ({ id, formState }: any) => {
- // Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
+ mutationFn: ({ id, formState }) => {
const sendBody = JSON.stringify(formState)
return fetch(`${endpoint}/peaks/${id}`, {
method: "PUT",
@@ -126,7 +121,7 @@ const useQueryClientFn = () => {
})
queryClient.setMutationDefaults(["peakDelete"], {
- mutationFn: ({ id }: any) => {
+ mutationFn: ({ id }) => {
return fetch(`${endpoint}/peaks/${id}`, {
method: "DELETE",
headers: {
diff --git a/apps/example/src/hooks/useUrlState.ts b/apps/example/src/hooks/useUrlState.ts
index a0fa2e630..98a6f2a93 100644
--- a/apps/example/src/hooks/useUrlState.ts
+++ b/apps/example/src/hooks/useUrlState.ts
@@ -1,6 +1,8 @@
-/* eslint-disable @typescript-eslint/no-unsafe-call */
+/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
+/* eslint-disable @typescript-eslint/no-unsafe-call*/
+
/*
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
@@ -8,6 +10,7 @@
import { useState, useEffect } from "react"
import { registerConsumer } from "@cloudoperators/juno-url-state-provider"
+
import {
useGlobalsActions,
useGlobalsTabIndex,
@@ -20,10 +23,8 @@ const TAB_INDEX = "t"
const CURRENT_PANEL = "p"
const CURRENT_MODAL = "m"
-const useUrlState = (key: any) => {
+const useUrlState = (key: string | undefined) => {
const [isURLRead, setIsURLRead] = useState(false)
- // it is possible to have two apps instances on the same page
- // int his case the key should be different per app
const urlStateManager = registerConsumer(key || DEFAULT_KEY)
// auth
@@ -38,33 +39,33 @@ const useUrlState = (key: any) => {
// Set initial state from URL (on login)
useEffect(() => {
- /* !!!IMPORTANT!!!
- don't read the url if we are already read it or if we are not logged in!!!!!
- */
if (isURLRead || !loggedIn) return
+
console.debug(`EXAMPLEAPP: (${key || DEFAULT_KEY}) setting up state from url:`, urlStateManager.currentState())
// READ the url state and set the state
const newTabIndex = urlStateManager.currentState()?.[TAB_INDEX]
const newCurrentPanel = urlStateManager.currentState()?.[CURRENT_PANEL]
const newCurrentModal = urlStateManager.currentState()?.[CURRENT_MODAL]
+
// SAVE the state
- if (newTabIndex) setTabIndex(newTabIndex)
- if (newCurrentPanel) setCurrentPanel(newCurrentPanel)
- if (newCurrentModal) setCurrentModal(newCurrentModal)
+ if (newTabIndex !== undefined) setTabIndex(newTabIndex)
+ if (newCurrentPanel !== undefined) setCurrentPanel(newCurrentPanel)
+ if (newCurrentModal !== undefined) setCurrentModal(newCurrentModal)
+
setIsURLRead(true)
- }, [loggedIn, setTabIndex, setCurrentPanel, setCurrentModal])
+ }, [isURLRead, loggedIn, key, setTabIndex, setCurrentPanel, setCurrentModal, urlStateManager])
// SYNC states to URL state
useEffect(() => {
- // don't sync if we are not logged in OR URL ist not yet read
if (!isURLRead || !loggedIn) return
+
urlStateManager.push({
[TAB_INDEX]: tabIndex,
[CURRENT_PANEL]: currentPanel,
[CURRENT_MODAL]: currentModal,
})
- }, [loggedIn, tabIndex, currentPanel, currentModal])
+ }, [loggedIn, tabIndex, currentPanel, currentModal, isURLRead, urlStateManager])
}
export default useUrlState
diff --git a/apps/example/src/index.tsx b/apps/example/src/index.tsx
index b1c9ae1e9..d62469f91 100644
--- a/apps/example/src/index.tsx
+++ b/apps/example/src/index.tsx
@@ -1,17 +1,13 @@
-/* eslint-disable @typescript-eslint/no-unsafe-return */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
-/* eslint-disable @typescript-eslint/no-unsafe-argument */
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/*
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
*/
-import { createRoot } from "react-dom/client"
+import { createRoot, Root } from "react-dom/client"
import React from "react"
-const getCurrentUrlWithoutFilename = () => {
+// Function to get the current URL without the filename
+const getCurrentUrlWithoutFilename = (): string => {
const currentUrl = window.location.href
const lastSlashIndex = currentUrl.lastIndexOf("/")
const lastSegment = currentUrl.slice(lastSlashIndex + 1)
@@ -20,7 +16,8 @@ const getCurrentUrlWithoutFilename = () => {
return lastSegment.trim() === "" || lastSegment.includes(".") ? currentUrl.slice(0, lastSlashIndex) : currentUrl
}
-const enableMocking = async (options: any) => {
+// Function to enable mocking
+const enableMocking = async (options: { endpoint: string }): Promise => {
/**
* Note: If you do not want to enable mocking in production, you can uncomment the following lines
* if (process.env.NODE_ENV !== "development") {
@@ -31,17 +28,36 @@ const enableMocking = async (options: any) => {
return startWorker(options)
}
-// export mount and unmount functions
-export const mount = async (container: any, options = {}) => {
- // @ts-expect-error TS(2339): Property 'props' does not exist on type '{}'.
- const endpoint = options?.props?.endpoint ?? getCurrentUrlWithoutFilename()
- await enableMocking({ endpoint }) // we need to first enable mocking before rendering the application
- const App = await import("./App")
- // @ts-expect-error TS(2339): Property 'root' does not exist on type '(container... Remove this comment to see the full error message
- mount.root = createRoot(container)
- // @ts-expect-error TS(2339): Property 'root' does not exist on type '(container... Remove this comment to see the full error message
- mount.root.render(React.createElement(App.default, { ...options?.props, endpoint }))
+interface MountOptions {
+ container: Element | DocumentFragment
+ props?: {
+ endpoint?: string
+ [key: string]: any
+ }
}
-// @ts-expect-error TS(2339): Property 'root' does not exist on type '(container... Remove this comment to see the full error message
-export const unmount = () => mount.root && mount.root.unmount()
+export const mount = async (
+ container: Element | DocumentFragment,
+ options: MountOptions = { container }
+): Promise => {
+ const endpoint = options.props?.endpoint ?? getCurrentUrlWithoutFilename()
+ await enableMocking({ endpoint }) // Enable mocking before rendering the application
+ const AppModule = await import("./App")
+ const App = AppModule.default
+
+ // Create a root if it does not exist
+ if (!mount.root) {
+ mount.root = createRoot(container)
+ }
+ mount.root.render()
+}
+
+// Unmount function
+export const unmount = (): void => {
+ if (mount.root) {
+ mount.root.unmount()
+ }
+}
+
+// Define the root property on the mount function to store the root instance
+mount.root = null as Root | null
diff --git a/apps/example/src/lib/store/createAuthSlice.ts b/apps/example/src/lib/store/createAuthSlice.ts
index b97d76c4a..c4e5a0c2b 100644
--- a/apps/example/src/lib/store/createAuthSlice.ts
+++ b/apps/example/src/lib/store/createAuthSlice.ts
@@ -1,18 +1,32 @@
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
+/* eslint-disable no-unused-vars */
+
/*
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
*/
+export interface AuthData {
+ auth: Record | null
+ isProcessing: boolean
+ loggedIn: boolean
+ error: string | null
+ data: Record | null
+ lastAction: Record
+ actions: {
+ setData: (data: Partial) => void
+ }
+}
+
+interface State {
+ auth: AuthData
+}
+
export const AUTH_ACTIONS = {
SIGN_ON: "signOn",
SIGN_OUT: "signOut",
}
-// @ts-expect-error TS(7006): Parameter 'set' implicitly has an 'any' type.
-const createAuthSlice = (set, _get) => ({
+const createAuthSlice = (set: (fn: (state: State) => State) => void, _get: () => State) => ({
auth: {
data: null,
isProcessing: false,
@@ -20,18 +34,20 @@ const createAuthSlice = (set, _get) => ({
error: null,
lastAction: {},
actions: {
- setData: (data: any) => {
+ setData: (data: Partial) => {
if (!data) return
set(
- (state: any) => ({
+ (state) => ({
auth: {
...state.auth,
- isProcessing: data?.isProcessing,
- loggedIn: data?.loggedIn,
- error: data?.error,
- data: data?.auth,
+ isProcessing: data?.isProcessing ?? state.auth.isProcessing,
+ loggedIn: data?.loggedIn ?? state.auth.loggedIn,
+ error: data?.error ?? state.auth.error,
+ data: data?.auth ?? state.auth.data,
+ lastAction: data?.lastAction ?? state.auth.lastAction,
},
}),
+ // @ts-ignore
false,
"auth/setData"
)
diff --git a/apps/example/src/lib/store/createGlobalsSlice.ts b/apps/example/src/lib/store/createGlobalsSlice.ts
index b1d0b3376..47a193560 100644
--- a/apps/example/src/lib/store/createGlobalsSlice.ts
+++ b/apps/example/src/lib/store/createGlobalsSlice.ts
@@ -1,14 +1,32 @@
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
-/* eslint-disable @typescript-eslint/no-unsafe-return */
+/* eslint-disable no-unused-vars */
+
/*
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
*/
-// @ts-expect-error TS(7006): Parameter 'set' implicitly has an 'any' type.
-const createGlobalsSlice = (set, _get) => ({
+export interface Globals {
+ endpoint: string
+ queryClientFnReady: boolean
+ tabIndex: number
+ currentModal: unknown
+ currentPanel: unknown
+ actions: GlobalsActions
+}
+
+interface GlobalsActions {
+ setEndpoint: (newEndpoint: string) => void
+ setTabIndex: (newTabIndex: number) => void
+ setCurrentModal: (newModal: unknown) => void
+ setCurrentPanel: (newPanel: unknown) => void
+ setQueryClientFnReady: (readiness: boolean) => void
+}
+
+interface State {
+ globals: Globals
+}
+
+const createGlobalsSlice = (set: (fn: (state: State) => State) => void, _get: () => State) => ({
globals: {
endpoint: "",
queryClientFnReady: false,
@@ -17,58 +35,63 @@ const createGlobalsSlice = (set, _get) => ({
currentPanel: null,
actions: {
- setEndpoint: (newEndpoint: any) =>
+ setEndpoint: (newEndpoint: string) =>
set(
- (state: any) => ({
+ (state) => ({
globals: {
...state.globals,
endpoint: newEndpoint,
},
}),
+ // @ts-ignore
false,
"globals.setEndpoint"
),
- setTabIndex: (newTabIndex: any) =>
+ setTabIndex: (newTabIndex: number) =>
set(
- (state: any) => ({
+ (state) => ({
globals: {
...state.globals,
tabIndex: newTabIndex,
},
}),
+ // @ts-ignore
false,
"globals.setTabIndex"
),
- setCurrentModal: (newModal: any) =>
+ setCurrentModal: (newModal: unknown) =>
set(
- (state: any) => ({
+ (state) => ({
globals: {
...state.globals,
currentModal: newModal,
},
}),
+ // @ts-ignore
false,
"globals.setCurrentModal"
),
- setCurrentPanel: (newPanel: any) =>
+ setCurrentPanel: (newPanel: unknown) =>
set(
- (state: any) => ({
+ (state) => ({
globals: {
...state.globals,
currentPanel: newPanel,
},
}),
+ // @ts-ignore
false,
"globals.setCurrentPanel"
),
- setQueryClientFnReady: (readiness: any) =>
+ setQueryClientFnReady: (readiness: boolean) =>
set(
- (state: any) => ({
+ (state) => ({
globals: {
...state.globals,
queryClientFnReady: readiness,
},
}),
+ // @ts-ignore
false,
"globals.setQueryClientFnReady"
),
diff --git a/apps/example/src/lib/store/index.ts b/apps/example/src/lib/store/index.ts
index 2a81adc19..39ef8ca18 100644
--- a/apps/example/src/lib/store/index.ts
+++ b/apps/example/src/lib/store/index.ts
@@ -5,13 +5,18 @@
import { createStore } from "zustand"
import { devtools } from "zustand/middleware"
-import createGlobalsSlice from "./createGlobalsSlice"
-import createAuthSlice from "./createAuthSlice"
+import createGlobalsSlice, { Globals } from "./createGlobalsSlice"
+import createAuthSlice, { AuthData } from "./createAuthSlice"
+
+type StoreState = Globals & AuthData
export default () =>
- createStore(
+ createStore(
+ // @ts-ignore
devtools((set, get) => ({
+ // @ts-ignore
...createGlobalsSlice(set, get),
+ // @ts-ignore
...createAuthSlice(set, get),
}))
)
diff --git a/apps/example/src/mocks/browser.ts b/apps/example/src/mocks/browser.ts
index 9455b30ba..f2ce8c54c 100644
--- a/apps/example/src/mocks/browser.ts
+++ b/apps/example/src/mocks/browser.ts
@@ -1,23 +1,27 @@
-/* eslint-disable @typescript-eslint/no-unsafe-call */
-/* eslint-disable @typescript-eslint/no-unsafe-argument */
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/*
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
*/
-import { setupWorker } from "msw/browser"
+import { setupWorker, SetupWorkerApi } from "msw/browser"
import getHandlers from "./getHandlers"
-let worker = null
+interface StartWorkerOptions {
+ endpoint: string
+ [key: string]: unknown
+}
+
+let worker: SetupWorkerApi | null = null
-export const startWorker = (options: any) => {
+export const startWorker = (options: StartWorkerOptions): Promise => {
+ // @ts-ignore
worker = setupWorker(...getHandlers(options))
+ // @ts-ignore
return worker.start({
serviceWorker: {
url: `${options.endpoint}/mockServiceWorker.js`,
},
- onUnhandledRequest(request: any, print: any) {
+ onUnhandledRequest(request, print) {
const url = new URL(request.url)
// Do not show unhandled request warning for the following paths
const listToIgnore = ["/src", "/@", "/node_modules"]
diff --git a/apps/example/src/mocks/db/index.ts b/apps/example/src/mocks/db/index.ts
index ca77d61e0..ba28a4f70 100644
--- a/apps/example/src/mocks/db/index.ts
+++ b/apps/example/src/mocks/db/index.ts
@@ -3,7 +3,19 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import peaks from "./peaks.json"
+import peaksData from "./peaks.json"
+
+export interface Peak {
+ id: number
+ name: string
+ height: string
+ region: string
+ mainrange: string
+ countries: string
+ url?: string
+}
+
+const peaks: Peak[] = peaksData
export default {
peaks,
diff --git a/apps/example/src/mocks/getHandlers.ts b/apps/example/src/mocks/getHandlers.ts
index 06b01e0e3..acd754547 100644
--- a/apps/example/src/mocks/getHandlers.ts
+++ b/apps/example/src/mocks/getHandlers.ts
@@ -1,61 +1,84 @@
-/* eslint-disable @typescript-eslint/no-unsafe-argument */
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
-/* eslint-disable @typescript-eslint/no-unsafe-return */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/*
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
*/
-import { http, HttpResponse } from "msw"
-
+import { http } from "msw"
import db from "./db"
-const getPeaks = ({ endpoint }: any) => {
- return http.get(`${endpoint}/peaks`, () => HttpResponse.json(db.peaks))
+interface Options {
+ endpoint: string
+}
+
+interface Peak {
+ id: number
+ name: string
+ height: string
+ region: string
+ mainrange: string
+ countries: string
+ url?: string
+}
+
+// Mock response handling utility
+class MockHttpResponse {
+ static json = (data: T) => {
+ return new Response(JSON.stringify(data), {
+ headers: { "Content-Type": "application/json" },
+ })
+ }
+
+ static notFound = (message: object) => {
+ return new Response(JSON.stringify(message), { status: 404 })
+ }
+}
+
+const getPeaks = ({ endpoint }: Options) => {
+ return http.get(`${endpoint}/peaks`, () => MockHttpResponse.json(db.peaks))
}
-const getPeak = ({ endpoint }: any) => {
- return http.get(`${endpoint}/peaks/:id`, ({ params }: any) => {
+const getPeak = ({ endpoint }: Options) => {
+ return http.get(`${endpoint}/peaks/:id`, ({ params }) => {
const { id } = params
- const peak = db.peaks.find((peak: any) => peak.id === Number(id))
- //@ts-ignore
- return peak ? HttpResponse.json(peak) : HttpResponse.notFound()
+ const peak = db.peaks.find((peak: Peak) => peak.id === Number(id))
+ if (peak) {
+ return MockHttpResponse.json(peak)
+ } else {
+ return MockHttpResponse.notFound({ message: "Peak not found" })
+ }
})
}
-const deletePeak = ({ endpoint }: any) => {
- return http.delete(`${endpoint}/peaks/:id`, ({ params }: any) => {
+const deletePeak = ({ endpoint }: Options) => {
+ return http.delete(`${endpoint}/peaks/:id`, ({ params }) => {
const { id } = params
- db.peaks = [...db.peaks.filter((peak: any) => peak.id !== Number(id))]
- return HttpResponse.json({})
+ db.peaks = db.peaks.filter((peak: Peak) => peak.id !== Number(id))
+ return MockHttpResponse.json({})
})
}
-const updatePeak = ({ endpoint }: any) => {
- return http.put(`${endpoint}/peaks/:id`, async ({ params, request }: any) => {
+const updatePeak = ({ endpoint }: Options) => {
+ return http.put(`${endpoint}/peaks/:id`, async ({ params, request }) => {
const { id } = params
- const updatedPeak = await request.json()
- db.peaks = db.peaks.map((peak: any) => (peak.id === Number(id) ? updatedPeak : peak))
- return HttpResponse.json({})
+ const updatedPeak = (await request.json()) as Peak
+ db.peaks = db.peaks.map((peak: Peak) => (peak.id === Number(id) ? updatedPeak : peak))
+ return MockHttpResponse.json({})
})
}
-const addPeak = ({ endpoint }: any) => {
- return http.post(`${endpoint}/peaks`, async ({ request }: any) => {
- const newPeak = await request.json()
- const id = Math.max(...db.peaks.map((peak: any) => peak.id)) + 1
+const addPeak = ({ endpoint }: Options) => {
+ return http.post(`${endpoint}/peaks`, async ({ request }) => {
+ const newPeak = (await request.json()) as Peak
+ const id = Math.max(...db.peaks.map((peak: Peak) => peak.id)) + 1
db.peaks = [...db.peaks, { ...newPeak, id }]
- return HttpResponse.json({})
+ return MockHttpResponse.json({})
})
}
-export default (options: any) => [
+export default (options: Options) => [
getPeaks(options),
getPeak(options),
deletePeak(options),
updatePeak(options),
addPeak(options),
- // add more request handlers here
]