Merge pull request #11686 from Budibase/cheeks-lab-day-portal-poc
Use apps within the portal
This commit is contained in:
commit
0578f96839
|
@ -101,7 +101,7 @@
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: var(--border-light);
|
border-bottom: var(--border-light);
|
||||||
padding: 0 24px;
|
padding: 0 var(--spacing-l);
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<script>
|
||||||
|
import { params, redirect } from "@roxi/routify"
|
||||||
|
import { apps } from "stores/portal"
|
||||||
|
|
||||||
|
$: app = $apps.find(app => app.appId === $params.appId)
|
||||||
|
$: {
|
||||||
|
if (!app) {
|
||||||
|
$redirect("../")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if app}
|
||||||
|
<slot />
|
||||||
|
{/if}
|
|
@ -0,0 +1,79 @@
|
||||||
|
<script>
|
||||||
|
import { params, goto } from "@roxi/routify"
|
||||||
|
import { apps, auth, sideBarCollapsed } from "stores/portal"
|
||||||
|
import { ActionButton } from "@budibase/bbui"
|
||||||
|
import { sdk } from "@budibase/shared-core"
|
||||||
|
|
||||||
|
$: app = $apps.find(app => app.appId === $params.appId)
|
||||||
|
$: iframeUrl = getIframeURL(app)
|
||||||
|
$: isBuilder = sdk.users.isBuilder($auth.user, app?.devId)
|
||||||
|
|
||||||
|
const getIframeURL = app => {
|
||||||
|
if (app.status === "published") {
|
||||||
|
return `/app${app.url}`
|
||||||
|
}
|
||||||
|
return `/${app.devId}`
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
{#if $sideBarCollapsed}
|
||||||
|
<ActionButton
|
||||||
|
quiet
|
||||||
|
icon="Rail"
|
||||||
|
on:click={() => sideBarCollapsed.set(false)}
|
||||||
|
>
|
||||||
|
Menu
|
||||||
|
</ActionButton>
|
||||||
|
{:else}
|
||||||
|
<ActionButton
|
||||||
|
quiet
|
||||||
|
icon="RailRightOpen"
|
||||||
|
on:click={() => sideBarCollapsed.set(true)}
|
||||||
|
>
|
||||||
|
Collapse
|
||||||
|
</ActionButton>
|
||||||
|
{/if}
|
||||||
|
{#if isBuilder}
|
||||||
|
<ActionButton
|
||||||
|
quiet
|
||||||
|
icon="Edit"
|
||||||
|
on:click={() => $goto(`../../app/${app.devId}`)}
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</ActionButton>
|
||||||
|
{/if}
|
||||||
|
<ActionButton
|
||||||
|
quiet
|
||||||
|
icon="LinkOut"
|
||||||
|
on:click={() => window.open(iframeUrl, "_blank")}
|
||||||
|
>
|
||||||
|
Fullscreen
|
||||||
|
</ActionButton>
|
||||||
|
</div>
|
||||||
|
<iframe src={iframeUrl} title={app.name} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: stretch;
|
||||||
|
padding: 0 var(--spacing-l) var(--spacing-l) var(--spacing-l);
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-xs);
|
||||||
|
flex: 0 0 50px;
|
||||||
|
}
|
||||||
|
iframe {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
border-radius: var(--spacing-s);
|
||||||
|
border: 1px solid var(--spectrum-global-color-gray-300);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,140 @@
|
||||||
|
<script>
|
||||||
|
import { Icon, Body } from "@budibase/bbui"
|
||||||
|
import { apps, sideBarCollapsed } from "stores/portal"
|
||||||
|
import { params, goto } from "@roxi/routify"
|
||||||
|
import { tick } from "svelte"
|
||||||
|
import NavItem from "components/common/NavItem.svelte"
|
||||||
|
|
||||||
|
let searchInput
|
||||||
|
let searchString
|
||||||
|
let searching = false
|
||||||
|
|
||||||
|
$: filteredApps = $apps.filter(app => {
|
||||||
|
return (
|
||||||
|
!searchString ||
|
||||||
|
app.name.toLowerCase().includes(searchString.toLowerCase())
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const startSearching = async () => {
|
||||||
|
searching = true
|
||||||
|
searchString = ""
|
||||||
|
await tick()
|
||||||
|
searchInput.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
const stopSearching = () => {
|
||||||
|
searching = false
|
||||||
|
searchString = ""
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="side-bar" class:collapsed={$sideBarCollapsed}>
|
||||||
|
<div class="side-bar-controls">
|
||||||
|
{#if searching}
|
||||||
|
<input
|
||||||
|
bind:this={searchInput}
|
||||||
|
bind:value={searchString}
|
||||||
|
placeholder="Search for apps"
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<Body size="S">Apps</Body>
|
||||||
|
<Icon name="Search" size="S" hoverable on:click={startSearching} />
|
||||||
|
{/if}
|
||||||
|
<div class="rotational" class:rotated={searching}>
|
||||||
|
<Icon
|
||||||
|
name="Add"
|
||||||
|
hoverable
|
||||||
|
on:click={searching ? stopSearching : () => $goto("./create")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="side-bar-nav">
|
||||||
|
<NavItem
|
||||||
|
icon="WebPages"
|
||||||
|
text="All apps"
|
||||||
|
on:click={() => $goto("./")}
|
||||||
|
selected={!$params.appId}
|
||||||
|
/>
|
||||||
|
{#each filteredApps as app}
|
||||||
|
<NavItem
|
||||||
|
text={app.name}
|
||||||
|
icon={app.icon?.name || "Apps"}
|
||||||
|
iconColor={app.icon?.color}
|
||||||
|
selected={$params.appId === app.appId}
|
||||||
|
on:click={() => $goto(`./${app.appId}`)}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.side-bar {
|
||||||
|
flex: 0 0 260px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
border-right: var(--border-light);
|
||||||
|
background: var(--spectrum-global-color-gray-100);
|
||||||
|
overflow: hidden;
|
||||||
|
transition: margin-left 300ms ease-out;
|
||||||
|
}
|
||||||
|
.side-bar.collapsed {
|
||||||
|
margin-left: -262px;
|
||||||
|
}
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.side-bar {
|
||||||
|
margin-left: -262px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-bar-controls {
|
||||||
|
flex: 0 0 50px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-l);
|
||||||
|
padding: 0 var(--spacing-l);
|
||||||
|
}
|
||||||
|
.side-bar-controls :global(.spectrum-Body),
|
||||||
|
.side-bar-controls input {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
.side-bar-controls :global(.spectrum-Icon) {
|
||||||
|
color: var(--spectrum-global-color-gray-700);
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
max-width: none;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
color: var(--spectrum-global-color-gray-800);
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 0;
|
||||||
|
transition: border 130ms ease-out;
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
background: inherit;
|
||||||
|
}
|
||||||
|
input::placeholder {
|
||||||
|
color: var(--spectrum-global-color-gray-700);
|
||||||
|
transition: color 130ms ease-out;
|
||||||
|
}
|
||||||
|
input:hover::placeholder {
|
||||||
|
color: var(--spectrum-global-color-gray-800);
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-bar-nav {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.rotational {
|
||||||
|
transition: transform 130ms ease-out;
|
||||||
|
}
|
||||||
|
div.rotational.rotated {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -11,6 +11,7 @@
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { redirect } from "@roxi/routify"
|
import { redirect } from "@roxi/routify"
|
||||||
import { sdk } from "@budibase/shared-core"
|
import { sdk } from "@budibase/shared-core"
|
||||||
|
import PortalSideBar from "./_components/PortalSideBar.svelte"
|
||||||
|
|
||||||
// Don't block loading if we've already hydrated state
|
// Don't block loading if we've already hydrated state
|
||||||
let loaded = $apps.length != null
|
let loaded = $apps.length != null
|
||||||
|
@ -44,5 +45,18 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if loaded}
|
{#if loaded}
|
||||||
<slot />
|
<div class="page">
|
||||||
|
<PortalSideBar />
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.page {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { writable } from "svelte/store"
|
||||||
|
|
||||||
export { organisation } from "./organisation"
|
export { organisation } from "./organisation"
|
||||||
export { users } from "./users"
|
export { users } from "./users"
|
||||||
export { admin } from "./admin"
|
export { admin } from "./admin"
|
||||||
|
@ -14,3 +16,5 @@ export { environment } from "./environment"
|
||||||
export { menu } from "./menu"
|
export { menu } from "./menu"
|
||||||
export { auditLogs } from "./auditLogs"
|
export { auditLogs } from "./auditLogs"
|
||||||
export { features } from "./features"
|
export { features } from "./features"
|
||||||
|
|
||||||
|
export const sideBarCollapsed = writable(false)
|
||||||
|
|
Loading…
Reference in New Issue