Move app list to admin portal

This commit is contained in:
Andrew Kingston 2021-05-06 13:59:06 +01:00
parent 845054a5b1
commit 69345b0c01
7 changed files with 139 additions and 96 deletions

View File

@ -1,11 +1,19 @@
<script> <script>
import { goto } from "@roxi/routify" import {
import { ActionButton, Heading } from "@budibase/bbui" Heading,
import { notifications } from "@budibase/bbui" Icon,
import Spinner from "components/common/Spinner.svelte" Body,
Layout,
ActionMenu,
MenuItem,
Link,
notifications,
} from "@budibase/bbui"
import download from "downloadjs" import download from "downloadjs"
import { gradient } from "actions"
export let name, _id export let name
export let _id
let appExportLoading = false let appExportLoading = false
@ -15,58 +23,59 @@
download( download(
`/api/backups/export?appId=${_id}&appname=${encodeURIComponent(name)}` `/api/backups/export?appId=${_id}&appname=${encodeURIComponent(name)}`
) )
notifications.success("App Export Complete.") notifications.success("App export complete")
} catch (err) { } catch (err) {
console.error(err) console.error(err)
notifications.error("App Export Failed.") notifications.error("App export failed")
} finally { } finally {
appExportLoading = false appExportLoading = false
} }
} }
</script> </script>
<div class="apps-card"> <Layout noPadding gap="XS">
<Heading size="S">{name}</Heading> <div class="preview" use:gradient />
<div class="card-footer" data-cy={`app-${name}`}> <div class="title">
<ActionButton on:click={() => $goto(`/builder/${_id}`)}> <Link href={`/builder/${_id}`}>
Open <Heading size="S">
{name} {name}
</Heading>
</ActionButton> </Link>
{#if appExportLoading} <ActionMenu>
<Spinner size="10" /> <Icon slot="control" name="More" hoverable />
{:else} <MenuItem on:click={exportApp} icon="Download">Export</MenuItem>
<ActionButton icon="Download" quiet /> </ActionMenu>
</div>
<div class="status">
<Body noPadding>Edited {Math.floor(1 + Math.random() * 10)} months ago</Body
>
{#if Math.random() > 0.5}
<Icon name="LockClosed" />
{/if} {/if}
</div> </div>
</div> </Layout>
<style> <style>
.apps-card { .preview {
background-color: var(--background); height: 135px;
padding: var(--spacing-xl) var(--spacing-xl) var(--spacing-xl) border-radius: var(--border-radius-s);
var(--spacing-xl); margin-bottom: var(--spacing-m);
max-width: 300px;
max-height: 150px;
border-radius: var(--border-radius-m);
border: var(--border-dark);
} }
.card-footer { .title,
.status {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center;
justify-content: space-between; justify-content: space-between;
margin-top: var(--spacing-m); align-items: center;
} }
i { .title :global(a) {
font-size: var(--font-size-l); text-decoration: none;
}
.title :global(h1:hover) {
color: var(--spectrum-global-color-blue-600);
cursor: pointer; cursor: pointer;
transition: 0.2s all; transition: color 130ms ease;
}
i:hover {
color: var(--blue);
} }
</style> </style>

View File

@ -1,50 +1,25 @@
<script> <script>
import { onMount } from "svelte"
import AppCard from "./AppCard.svelte" import AppCard from "./AppCard.svelte"
import { Heading, Divider } from "@budibase/bbui" import { apps } from "stores/portal"
import Spinner from "components/common/Spinner.svelte"
import { get } from "builderStore/api"
let promise = getApps() onMount(apps.load)
async function getApps() {
const res = await get("/api/applications")
const json = await res.json()
if (res.ok) {
return json
} else {
throw new Error(json)
}
}
</script> </script>
<div class="root"> {#if $apps.length}
<Heading size="M">Your Apps</Heading> <div class="appList">
<Divider size="M" /> {#each $apps as app}
{#await promise}
<div class="spinner-container">
<Spinner size="30" />
</div>
{:then apps}
<div class="apps">
{#each apps as app}
<AppCard {...app} /> <AppCard {...app} />
{/each} {/each}
</div> </div>
{:catch err} {:else}
<h1 style="color:red">{err}</h1> <div>No apps</div>
{/await} {/if}
</div>
<style> <style>
.root { .appList {
margin-top: 10px;
}
.apps {
margin-top: var(--layout-m);
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); grid-gap: 50px;
grid-gap: var(--layout-s); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
justify-content: start;
} }
</style> </style>

View File

@ -1,6 +1,5 @@
<script> <script>
import api from "builderStore/api" import api from "builderStore/api"
import AppList from "components/start/AppList.svelte"
import { get } from "builderStore/api" import { get } from "builderStore/api"
import CreateAppModal from "components/start/CreateAppModal.svelte" import CreateAppModal from "components/start/CreateAppModal.svelte"
import { Button, Heading, Modal, ButtonGroup } from "@budibase/bbui" import { Button, Heading, Modal, ButtonGroup } from "@budibase/bbui"
@ -72,8 +71,6 @@
</div> </div>
<!-- <TemplateList onSelect={selectTemplate} /> --> <!-- <TemplateList onSelect={selectTemplate} /> -->
<AppList />
</div> </div>
<Modal bind:this={modal} padding={false} width="600px" on:hide={closeModal}> <Modal bind:this={modal} padding={false} width="600px" on:hide={closeModal}>

View File

@ -10,8 +10,11 @@
SideNavigation as Navigation, SideNavigation as Navigation,
SideNavigationItem as Item, SideNavigationItem as Item,
} from "@budibase/bbui" } from "@budibase/bbui"
import { organisation } from "stores/portal" import { organisation, apps } from "stores/portal"
organisation.init() organisation.init()
apps.load()
console.log("loading")
let onBoardingProgress, user let onBoardingProgress, user

View File

@ -1,27 +1,58 @@
<script> <script>
import { Heading, Layout } from "@budibase/bbui" import {
Heading,
Layout,
Button,
ActionButton,
ActionGroup,
Select,
} from "@budibase/bbui"
import AppList from "components/start/AppList.svelte"
let layout = "grid"
</script> </script>
<Layout noPadding> <Layout noPadding>
<div> <div class="title">
<Heading>Apps</Heading> <Heading>Apps</Heading>
<Button primary>Create new app</Button>
</div> </div>
<div class="appList"> <div class="filter">
{#each new Array(10) as _} <div class="select">
<div class="app" /> <Select quiet placeholder="Filter by groups" />
{/each}
</div> </div>
<ActionGroup>
<ActionButton
on:click={() => (layout = "grid")}
selected={layout === "grid"}
quiet
icon="ClassicGridView"
/>
<ActionButton
on:click={() => (layout = "table")}
selected={layout === "table"}
quiet
icon="ViewRow"
/>
</ActionGroup>
</div>
{#if layout === "grid"}
<AppList />
{:else}
Table
{/if}
</Layout> </Layout>
<style> <style>
.appList { .title,
display: grid; .filter {
grid-gap: 50px; display: flex;
grid-template-columns: repeat(auto-fill, 300px); flex-direction: row;
justify-content: space-between;
align-items: center;
} }
.app {
height: 130px; .select {
border-radius: 4px; width: 110px;
background-color: var(--spectrum-global-color-gray-200);
} }
</style> </style>

View File

@ -0,0 +1,27 @@
import { writable } from "svelte/store"
import { get } from "builderStore/api"
export function createAppStore() {
const store = writable([])
async function load() {
try {
const res = await get("/api/applications")
const json = await res.json()
if (res.ok && Array.isArray(json)) {
store.set(json)
} else {
store.set([])
}
} catch (error) {
store.set([])
}
}
return {
subscribe: store.subscribe,
load,
}
}
export const apps = createAppStore()

View File

@ -1,2 +1,3 @@
export { organisation } from "./organisation" export { organisation } from "./organisation"
export { admin } from "./admin" export { admin } from "./admin"
export { apps } from "./apps"