Skip to content

Commit

Permalink
Importmaps v2 (#257)
Browse files Browse the repository at this point in the history
switch to importmap
  • Loading branch information
andypf authored Jan 6, 2023
1 parent 8f0184e commit dd4151f
Show file tree
Hide file tree
Showing 176 changed files with 4,888 additions and 2,209 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ci
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ node_modules
!.yarn/versions
.pnp.*

scripts/test_data
scripts/im.json
scripts/manifest.json

# testing
/coverage

Expand Down
2 changes: 1 addition & 1 deletion apps/keymanager/.env → apps/assets-overview/.env
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Copy these attr to .env.local to start the app
ENDPOINT="https://endpoint/api/v1"
MANIFEST_URL="https://endpoint/api/v1"
# Possible values for theme: "theme-dark" or "theme-light", default is "theme-dark"
THEME="theme-dark"
# Set to true if app is to be embedded in another existing app or page, like e.g. Elektra
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
74 changes: 74 additions & 0 deletions apps/assets-overview/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"name": "assets-overview",
"version": "1.0.0",
"source": "src/index.js",
"module": "build/index.js",
"private": true,
"devDependencies": {
"@babel/core": "^7.20.2",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"@svgr/webpack": "^6.2.1",
"@testing-library/dom": "^8.19.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3",
"assert": "^2.0.0",
"autoprefixer": "^10.4.2",
"babel-jest": "^29.3.1",
"babel-loader": "^8.2.3",
"babel-plugin-macros": "^3.1.0",
"buffer": "^6.0.3",
"bundle-loader": "^0.5.6",
"clean-webpack-plugin": "^4.0.0",
"css-loader": "^6.6.0",
"css-minimizer-webpack-plugin": "^3.4.1",
"custom-event-polyfill": "^1.0.7",
"dotenv-webpack": "^7.1.0",
"glob": "^7.2.0",
"html-webpack-plugin": "^5.4.0",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
"juno-ui-components": "workspace:*",
"luxon": "^2.3.0",
"mini-css-extract-plugin": "^2.5.3",
"os-browserify": "^0.3.0",
"path-browserify": "^1.0.1",
"postcss": "^8.4.6",
"postcss-loader": "^6.2.1",
"process": "^0.11.10",
"prop-types": "^15.8.1",
"purgecss-webpack-plugin": "^4.1.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-query": "^3.39.2",
"react-refresh": "^0.10.0",
"react-test-renderer": "^18.2.0",
"sass-loader": "^12.4.0",
"shadow-dom-testing-library": "^1.7.1",
"tailwindcss": "^3.0.24",
"url-state-provider": "workspace:*",
"util": "^0.12.4",
"webpack": "^5.75.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4",
"zustand": "^4.1.1"
},
"scripts": {
"start": "PORT=$APP_PORT webpack serve --mode development --hot",
"test": "jest",
"build": "webpack --mode production",
"production": "PORT=$APP_PORT webpack serve --mode production"
},
"peerDependencies": {
"custom-event-polyfill": "^1.0.7",
"juno-ui-components": "*",
"luxon": "^2.3.0",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-query": "^3.39.2",
"url-state-provider": "*",
"zustand": "^4.1.1"
}
}
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="apple-touch-icon" href="apple-touch-icon.png" />

<title>Converged Cloud Keymanager</title>
<title>App Template</title>
<style>
html {
height: 100vh;
Expand All @@ -33,5 +33,11 @@
</script>

<div id="root"></div>

<!-- <script
src="https://assets.juno.qa-de-1.cloud.sap/apps/widget-loader@latest/build/app.js"
data-url="./index.js"
data-props-manifest-url="https://assets.juno.qa-de-1.cloud.sap/manifest.json"
></script> -->
</body>
</html>
File renamed without changes.
File renamed without changes.
65 changes: 65 additions & 0 deletions apps/assets-overview/src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from "react"

import useStore from "./store"
import { AppShell } from "juno-ui-components"
import { QueryClient, QueryClientProvider } from "react-query"
import AppContent from "./AppContent"
import styles from "./styles.scss"
import StyleProvider from "juno-ui-components"

/* IMPORTANT: Replace this with your app's name */
const URL_STATE_KEY = "template"
/* --------------------------- */

const App = (props) => {
const setManifestUrl = useStore((state) => state.setManifestUrl)
const setUrlStateKey = useStore((state) => state.setUrlStateKey)
const { embedded } = props
// 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
React.useEffect(() => {
// set to empty string to fetch local test data in dev mode
setManifestUrl(props.manifestUrl)
setUrlStateKey(URL_STATE_KEY)
}, [])

return (
<QueryClientProvider client={queryClient}>
<AppShell
pageHeader="Converged Cloud | Juno Assets Overview"
contentHeading=""
embedded={embedded === "true"}
>
<AppContent props={props} />
</AppShell>
</QueryClientProvider>
)
}

const StyledApp = (props) => {
// console.log(":::::::::::::::::1", props)
// default props
props = {
manifestUrl: process.env.MANIFEST_URL,
theme: process.env.THEME,
embedded: process.env.EMBEDDED,
...props,
}

// console.log(":::::::::::::::::2", props)
return (
<StyleProvider
stylesWrapper="shadowRoot"
theme={`${props.theme ? props.theme : "theme-dark"}`}
>
{/* load styles inside the shadow dom */}
<style>{styles.toString()}</style>
<App {...props} />
</StyleProvider>
)
}

export default StyledApp
17 changes: 17 additions & 0 deletions apps/assets-overview/src/App.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react"
import { render, act, waitFor } from "@testing-library/react"
// support shadow dom queries
// https://reactjsexample.com/an-extension-of-dom-testing-library-to-provide-hooks-into-the-shadow-dom/
import { screen } from "shadow-dom-testing-library"
import App from "./App"

import * as actions from "./actions"
jest.mock("./actions.js")
actions.fetchAssetsManifest = jest.fn().mockResolvedValue({})

test("renders app", async () => {
await act(() => render(<App />))

let loginTitle = await screen.queryAllByShadowText(/Converged Cloud/i)
expect(loginTitle.length > 0).toBe(true)
})
97 changes: 97 additions & 0 deletions apps/assets-overview/src/AppContent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from "react"
import {
Button,
ContentAreaToolbar,
Container,
IntroBox,
Message,
Spinner,
DataGrid,
DataGridRow,
DataGridHeadCell,
DataGridCell,
TabPanel,
CodeBlock,
} from "juno-ui-components"
import useStore from "./store"
import NewItemForm from "./components/NewItemForm"
import heroImage from "./img/app_bg_example.svg?url"
import { useQuery } from "react-query"
import { fetchAssetsManifest } from "./actions"
import { currentState, push } from "url-state-provider"

const AppContent = (props) => {
const manifestUrl = useStore((state) => state.manifestUrl)
const urlStateKey = useStore((state) => state.urlStateKey)

const { isLoading, isError, data, error } = useQuery(
manifestUrl,
fetchAssetsManifest,
{
enabled: !!manifestUrl,
// enable the query also if the endpoint is set. For fetching local
// data is not necessary since it should be empty
// enabled: !!endpoint,
// If set to Infinity, the data will never be considered stale
// until a browser reload is triggered
staleTime: Infinity,
// refer to this documentation to see more options
// https://tanstack.com/query/v4/docs/guides/queries
}
)

const openNewItemForm = () => {
const urlState = currentState(urlStateKey)
push(urlStateKey, { ...urlState, newItemFormOpened: true })
}

if (isLoading) return <Spinner variant="primary" />
if (isError)
return (
<Message variant="danger">{`${error.statusCode}, ${error.message}`}</Message>
)
if (!data) return null

return (
<DataGrid columns={7}>
<DataGridRow>
<DataGridHeadCell>Name</DataGridHeadCell>
<DataGridHeadCell>Type</DataGridHeadCell>
<DataGridHeadCell>Version</DataGridHeadCell>
<DataGridHeadCell>Entry File</DataGridHeadCell>
<DataGridHeadCell>Entry Dir</DataGridHeadCell>
<DataGridHeadCell>Size</DataGridHeadCell>
<DataGridHeadCell>Updated At</DataGridHeadCell>
</DataGridRow>
{Object.keys(data)
.sort()
.map((assetName, i) =>
Object.keys(data[assetName])
.sort()
.map((version, j) => (
<DataGridRow key={`${i}-${j}`}>
<DataGridCell>{j === 0 ? assetName : ""}</DataGridCell>
<DataGridCell>
{j === 0 ? data[assetName][version]["type"] : ""}
</DataGridCell>
<DataGridCell>{version}</DataGridCell>
<DataGridCell>
{data[assetName][version]["entryFile"]}
</DataGridCell>
<DataGridCell>
{data[assetName][version]["entryDir"]}
</DataGridCell>
<DataGridCell>
{data[assetName][version]["sizeHuman"]}
</DataGridCell>
<DataGridCell>
{data[assetName][version]["updatedAt"]}
</DataGridCell>
</DataGridRow>
))
)}
</DataGrid>
)
}

export default AppContent
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,23 @@ const checkStatus = (response) => {
return response.text().then((message) => {
var error = new HTTPError(response.status, message || response.statusText)
error.statusCode = response.status
// throw error
return Promise.reject(error)
})
}
}

// Example fetch call. Adjust as needed for your API
export const exampleFetch = (input, options) => {
return fetch(
`${ENDPOINT}/query?input=${input}${encodeUrlParamsFromObject(options)}`,
{
method: "GET",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
},
}
).then(checkStatus)
export const fetchAssetsManifest = ({ queryKey }) => {
const [manifestUrl] = queryKey
return fetch(manifestUrl, {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
})
.then(checkStatus)
.then((response) => {
return response.json()
})
}
47 changes: 47 additions & 0 deletions apps/assets-overview/src/components/NewItemForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, { useState, useEffect } from "react"

import { Button, Panel, PanelBody, PanelFooter } from "juno-ui-components"
import useStore from "../store"
import { currentState, push, addOnChangeListener } from "url-state-provider"

const NewItemFormFooter = ({ onCancelCallback }) => {
return (
<PanelFooter>
<Button variant="subdued" onClick={onCancelCallback}>
Cancel
</Button>
<Button variant="primary">Do it</Button>
</PanelFooter>
)
}

const NewItemForm = () => {
const urlStateKey = useStore((state) => state.urlStateKey)
const urlState = currentState(urlStateKey)
const [opened, setOpened] = useState(false)

// wait until the global state is set to fetch the url state
useEffect(() => {
setOpened(urlState?.newItemFormOpened)
}, [urlStateKey])

// call close reducer from url store
const onClose = () => {
push(urlStateKey, { ...urlState, newItemFormOpened: false })
}

// this listener reacts on any change on the url state
addOnChangeListener(urlStateKey, (newState) => {
setOpened(newState?.newItemFormOpened)
})

return (
<Panel heading="Panel Title" opened={opened} onClose={onClose}>
<PanelBody footer={<NewItemFormFooter onCancelCallback={onClose} />}>
<div>Panel Content here</div>
</PanelBody>
</Panel>
)
}

export default NewItemForm
Loading

0 comments on commit dd4151f

Please sign in to comment.