Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(example): improve example app types (1st iteration) #734

Merged
merged 11 commits into from
Jan 31, 2025
5 changes: 5 additions & 0 deletions .changeset/fair-ears-shave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudoperators/juno-app-example": minor
---

Improve example app types
15 changes: 7 additions & 8 deletions apps/example/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,19 @@
import React from "react"
import { render } from "@testing-library/react"
import App from "./App"
import { describe } from "node:test"
import { describe, it, expect, vi } from "vitest"
import { screen } from "shadow-dom-testing-library"

// Mock the styles
vi.mock("./styles.module.scss", () => ({
default: new Proxy(new Object(), {
// @ts-ignore
toString() {
return "/*TEST STYLES*/"
},
}),
default: new Proxy(
{},
{
get: () => "/*TEST STYLES*/",
}
),
}))

// eslint-disable-next-line @typescript-eslint/no-floating-promises
describe("App", () => {
it("should render the App component", () => {
render(<App id="123" />)
Expand Down
82 changes: 31 additions & 51 deletions apps/example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-call */
barsukov marked this conversation as resolved.
Show resolved Hide resolved

/*
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useEffect } from "react"
import PropTypes from "prop-types"
import React, { useEffect, useMemo } from "react"

// @ts-ignore
import styles from "./styles.scss?inline"

import MonorepoChecker from "./components/MonorepoChecker"

import {
AppShellProvider,
AppShell,
Expand All @@ -24,87 +23,74 @@ import {
} from "@cloudoperators/juno-ui-components"
import { mockedSession } from "@cloudoperators/juno-oauth"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { MessagesProvider } from "@cloudoperators/juno-messages-provider"

import AppContent from "./components/AppContent"
import HeaderUser from "./components/auth/HeaderUser"
import AsyncWorker from "./components/AsyncWorker"
import StoreProvider, { useGlobalsActions, useAuthActions } from "./components/StoreProvider"
import { MessagesProvider } from "@cloudoperators/juno-messages-provider"

const App = (props = {}) => {
interface AppProps {
endpoint?: string
embedded?: boolean
id?: string
theme?: string
}

const App: React.FC<AppProps> = ({ endpoint, embedded, id }) => {
// @ts-ignore
const { setEndpoint } = useGlobalsActions()
// @ts-ignore
const { setData } = useAuthActions()

// Create query client which it can be used from overall in the app
const queryClient = new QueryClient()

// on app initial load save Endpoint and URL_STATE_KEY so it can be
// used from overall in the application
useEffect(() => {
// set default endpoint so the useQueryClientFn can be used
// @ts-ignore
setEndpoint(props.endpoint)
}, [])
setEndpoint(endpoint || "")
}, [endpoint, setEndpoint])

// fetch the mocked auth object and save it globally
const oidc = React.useMemo(() => {
// force fetch mocked session
return mockedSession({
initialLogin: true,
onUpdate: (data: any) => {
setData(data)
},
})
}, [])
const oidc = useMemo(
() =>
mockedSession({
initialLogin: true,
onUpdate: setData,
}),
[setData]
)

// @ts-ignore
console.debug("[exampleapp] embedded mode:", props.embedded)
console.debug("[exampleapp] embedded mode:", embedded)

return (
<QueryClientProvider client={queryClient}>
<MonorepoChecker></MonorepoChecker>
{/* @ts-ignore */}
<AsyncWorker consumerId={props.id} />
{/* @ts-ignore */}
<AsyncWorker consumerId={id} />
<AppShell
//@ts-ignore
embedded={props.embedded === "true" || props.embedded === true}
// @ts-ignore
embedded={embedded === "true" || embedded === true}
pageHeader={
//@ts-ignore
<PageHeader heading="Converged Cloud | Example App">
{/* @ts-ignore */}
<HeaderUser login={oidc.login} logout={oidc.logout} />
</PageHeader>
}
topNavigation={
//@ts-ignore
<TopNavigation>
{/* @ts-ignore */}
<TopNavigationItem icon="home" label="Home" />
{/* @ts-ignore */}
<TopNavigationItem active label="Navigation Item" />
</TopNavigation>
}
>
<Container py>
{/* @ts-ignore */}
<AppContent props={props} />
<AppContent />
</Container>
</AppShell>
</QueryClientProvider>
)
}

App.propTypes = {
endpoint: PropTypes.string,
embedded: PropTypes.bool,
id: PropTypes.string,
}

const StyledApp = (props: any) => {
const StyledApp: React.FC<AppProps> = (props) => {
return (
<AppShellProvider theme={`${props.theme ? props.theme : "theme-dark"}`}>
// @ts-ignore
<AppShellProvider theme={props.theme || "theme-dark"}>
{/* load styles inside the shadow dom */}
<style>{styles.toString()}</style>
<MessagesProvider>
Expand All @@ -116,10 +102,4 @@ const StyledApp = (props: any) => {
)
}

StyledApp.propTypes = {
theme: PropTypes.string,
embedded: PropTypes.bool,
endpoint: PropTypes.string,
id: PropTypes.string,
}
export default StyledApp
28 changes: 7 additions & 21 deletions apps/example/src/components/AppContent.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* 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
Expand All @@ -22,14 +22,14 @@ import {
} from "@cloudoperators/juno-ui-components"
import { useGlobalsActions, useGlobalsTabIndex, useAuthLoggedIn, useAuthError } from "./StoreProvider"
import { useActions, Messages } from "@cloudoperators/juno-messages-provider"

import ModalManager from "./ModalManager"
import PanelManager from "./PanelManager"
import Peaks from "./peaks/Peaks"
import WelcomeView from "./WelcomeView"
import PositionArea from "./PositionArea"

const AppContent = () => {
// @ts-ignore
const AppContent: React.FC = () => {
const { setTabIndex, setCurrentModal } = useGlobalsActions()
const loggedIn = useAuthLoggedIn()
const authError = useAuthError()
Expand All @@ -44,9 +44,9 @@ const AppContent = () => {
text: JSON.stringify(authError),
})
}
}, [authError])
}, [authError, addMessage])

const onTabSelected = (index: any) => {
const onTabSelected = (index: number) => {
setTabIndex(index)
}

Expand All @@ -55,23 +55,17 @@ const AppContent = () => {
{loggedIn && !authError ? (
<>
<Breadcrumb>
{/* @ts-ignore */}
<BreadcrumbItem icon="home" label="Example App Home" />
</Breadcrumb>

<Container py>
{/* @ts-ignore */}
<MainTabs selectedIndex={tabIndex} onSelect={onTabSelected}>
{/* @ts-ignore */}
<TabList>
{/* @ts-ignore */}
<Tab>Peaks</Tab>
{/* @ts-ignore */}
<Tab>Tab Two</Tab>
</TabList>

<TabPanel>
{/* @ts-ignore */}
<Container py px={false}>
{/* Set the background graphic using tailwind background image syntax as below. The image must exist at the specified location in your app */}
{/*<IntroBox variant="hero" heroImage="bg-[url('img/app_bg_example.svg')]">
Expand All @@ -84,28 +78,20 @@ const AppContent = () => {
</Container>
</TabPanel>
<TabPanel>
{/* @ts-ignore */}
<Container py px={false}>
<p>Test a panel pressing the Button</p>
{/* @ts-ignore */}
<Button label="Button" onClick={() => setCurrentModal("TestModal")} />
<Button label="Button" onClick={() => setCurrentModal({ type: "TestModal" })} />
<p>Test a select</p>
{/* @ts-ignore */}
<Select
name="filter"
className="filter-label-select w-64 mb-0"
label="Filter"
onChange={(e: any) => console.debug(e)}
onChange={(e) => console.debug(e)}
>
{/* @ts-ignore */}
<SelectOption value="0" label="Option 0" />
{/* @ts-ignore */}
<SelectOption value="1" label="Option 1" />
{/* @ts-ignore */}
<SelectOption value="2" label="Option 2" />
{/* @ts-ignore */}
<SelectOption value="3" label="Option 3" />
{/* @ts-ignore */}
<SelectOption value="4" label="Option 4" />
</Select>
</Container>
Expand Down
13 changes: 7 additions & 6 deletions apps/example/src/components/AsyncWorker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@
* SPDX-License-Identifier: Apache-2.0
*/

import PropTypes from "prop-types"
import React from "react"

import useQueryClientFn from "../hooks/useQueryClientFn"
import useUrlState from "../hooks/useUrlState"

const AsyncWorker = ({ consumerId }: any) => {
interface AsyncWorkerProps {
consumerId: string
}

const AsyncWorker: React.FC<AsyncWorkerProps> = ({ consumerId }) => {
useQueryClientFn()
useUrlState(consumerId)
return null
}

AsyncWorker.propTypes = {
consumerId: PropTypes.string.isRequired,
}

export default AsyncWorker
3 changes: 2 additions & 1 deletion apps/example/src/components/ModalManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
*/

import React from "react"

import { useGlobalsCurrentModal } from "./StoreProvider"
import TestModal from "./TestModal"

const ModalManager = () => {
const ModalManager: React.FC = () => {
const currentModal = useGlobalsCurrentModal()

switch (currentModal) {
Expand Down
32 changes: 0 additions & 32 deletions apps/example/src/components/MonorepoChecker.tsx

This file was deleted.

Loading
Loading