Note, this functionality is currently experimental. Please help us flesh it out and make it better!
Sometimes your product contains functionality or pages that just won't fit in with the platform paradigm. But we still want to provide a unified interface for our users. That's where external components comes in. You can mount a page of your app into the platform using an iframe or if you give us a js component we'll run that for you too.
You'll have to be in a ProductBuilder-enabled tenant to get this to work. Go create a new product and then in the left side bar click "+ New Menu Item" and select either Iframe or JS Component. With iframes, we'll mount your app in the main area on the right. With JS Components, we expect you to hand us an ES Module with 2 exports: start/1 and stop/1. We'll call start/1 anytime your app is activated and stop/1 when the user navigates to a different menu item. You'll be passed a reference to the DOM node where you should mount your app as the first and only argument in both of those functions.
Your URL can contain any of the following substitutions:
We haven't decided what sources we'll allow into the platform quite yet. We are currently NOT sending a CSP in development or in the Build PRs enviromnent. So you can test out your components on local.kualibuild.com and will be able to share them with others through buildprs.kualibuild.com. The CSP in production is pretty strict so odds are you won't be able to run your component there quite yet. The components you mount in a non-local environment will need to be hosted on an https domain; I'd suggest using netlify as it's super easy to use and free!
We're thinking we'll let in anything from *.kuali.co, *.kualibuild.com, *.kuali.cloud, and maybe some other site dedicated for the purpose like *.kualiplatformcontent.com or something. If you're an iframe, it'll be easiest if you host your module under the same domain platform is running on. That way you'll get the authed user's cookie and can make requests against platform apis. Better support for other hosts will come once we've added OAuth support to identity.
// this example needs no bundling. Save it to a file, host it, and then reference itexport function start (element) {console.log('mounting my app')element.style = 'background:lightblue;font-size:72px'element.innerText = 'Hello Product Builder!'}export function stop () {console.log('unmounting my app')}
// compile this with:// esbuild --bundle example.jsx --outdir=dist --format=esmimport React from 'react'import ReactDOM from 'react-dom'function App () {const [count, setCount] = React.useState(0)return (<div className='flex h-full flex-col items-center justify-center'><h1>React Counter Example</h1><div className='flex items-center'><buttonclassName='kp-button-solid'onClick={() => setCount(count => count - 1)}>-</button><div className='px-2 text-3xl'>{count}</div><buttonclassName='kp-button-solid'onClick={() => setCount(count => count + 1)}>+</button></div></div>)}export function start (el) {const root = ReactDOM.createRoot(el)root.render(<App />)return root}export function stop (root) {root.unmount()}