Simplify app layout and add option to delete apps
This commit is contained in:
parent
df607e78eb
commit
0b1b4d2aae
|
@ -7,6 +7,7 @@
|
||||||
export let cancelText = "Cancel"
|
export let cancelText = "Cancel"
|
||||||
export let onOk = undefined
|
export let onOk = undefined
|
||||||
export let onCancel = undefined
|
export let onCancel = undefined
|
||||||
|
export let warning = true
|
||||||
|
|
||||||
let modal
|
let modal
|
||||||
|
|
||||||
|
@ -19,7 +20,13 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal bind:this={modal} on:hide={onCancel}>
|
<Modal bind:this={modal} on:hide={onCancel}>
|
||||||
<ModalContent onConfirm={onOk} {title} confirmText={okText} {cancelText} red>
|
<ModalContent
|
||||||
|
onConfirm={onOk}
|
||||||
|
{title}
|
||||||
|
confirmText={okText}
|
||||||
|
{cancelText}
|
||||||
|
{warning}
|
||||||
|
>
|
||||||
<Body size="S">
|
<Body size="S">
|
||||||
{body}
|
{body}
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
@ -13,8 +13,7 @@
|
||||||
|
|
||||||
export let app
|
export let app
|
||||||
export let exportApp
|
export let exportApp
|
||||||
|
export let deleteApp
|
||||||
let appExportLoading = false
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
|
@ -28,9 +27,12 @@
|
||||||
</Link>
|
</Link>
|
||||||
<ActionMenu align="right">
|
<ActionMenu align="right">
|
||||||
<Icon slot="control" name="More" hoverable />
|
<Icon slot="control" name="More" hoverable />
|
||||||
<MenuItem on:click={() => exportApp(app)} icon="Download"
|
<MenuItem on:click={() => exportApp(app)} icon="Download">
|
||||||
>Export</MenuItem
|
Export
|
||||||
>
|
</MenuItem>
|
||||||
|
<MenuItem on:click={() => deleteApp(app)} icon="Delete">
|
||||||
|
Delete
|
||||||
|
</MenuItem>
|
||||||
</ActionMenu>
|
</ActionMenu>
|
||||||
</div>
|
</div>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
<script>
|
|
||||||
import AppCard from "./AppCard.svelte"
|
|
||||||
import { apps } from "stores/portal"
|
|
||||||
|
|
||||||
export let exportApp
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if $apps.length}
|
|
||||||
<div class="appList">
|
|
||||||
{#each $apps as app}
|
|
||||||
<AppCard {exportApp} {app} />
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.appList {
|
|
||||||
display: grid;
|
|
||||||
grid-gap: 50px;
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
<script>
|
||||||
|
import { gradient } from "actions"
|
||||||
|
import {
|
||||||
|
Heading,
|
||||||
|
Button,
|
||||||
|
Icon,
|
||||||
|
ActionMenu,
|
||||||
|
MenuItem,
|
||||||
|
Link,
|
||||||
|
} from "@budibase/bbui"
|
||||||
|
import { url } from "@roxi/routify"
|
||||||
|
|
||||||
|
export let app
|
||||||
|
export let openApp
|
||||||
|
export let exportApp
|
||||||
|
export let deleteApp
|
||||||
|
export let last
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="title" class:last>
|
||||||
|
<div class="preview" use:gradient />
|
||||||
|
<Link href={$url(`../../app/${app._id}`)}>
|
||||||
|
<Heading size="XS">
|
||||||
|
{app.name}
|
||||||
|
</Heading>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div class:last>
|
||||||
|
Edited {Math.round(Math.random() * 10 + 1)} months ago
|
||||||
|
</div>
|
||||||
|
<div class:last>
|
||||||
|
{#if Math.random() < 0.33}
|
||||||
|
<div class="status status--open" />
|
||||||
|
Open
|
||||||
|
{:else if Math.random() < 0.33}
|
||||||
|
<div class="status status--locked-other" />
|
||||||
|
Locked by Will Wheaton
|
||||||
|
{:else}
|
||||||
|
<div class="status status--locked-you" />
|
||||||
|
Locked by you
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class:last>
|
||||||
|
<Button on:click={() => openApp(app)} size="S" secondary>Open</Button>
|
||||||
|
<ActionMenu align="right">
|
||||||
|
<Icon hoverable slot="control" name="More" />
|
||||||
|
<MenuItem on:click={() => exportApp(app)} icon="Download">Export</MenuItem>
|
||||||
|
<MenuItem on:click={() => deleteApp(app)} icon="Delete">Delete</MenuItem>
|
||||||
|
</ActionMenu>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.preview {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
border-radius: var(--border-radius-s);
|
||||||
|
}
|
||||||
|
.title :global(a) {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.title :global(h1:hover) {
|
||||||
|
color: var(--spectrum-global-color-blue-600);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 130ms ease;
|
||||||
|
}
|
||||||
|
.status {
|
||||||
|
height: 10px;
|
||||||
|
width: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.status--locked-you {
|
||||||
|
background-color: var(--spectrum-global-color-orange-600);
|
||||||
|
}
|
||||||
|
.status--locked-other {
|
||||||
|
background-color: var(--spectrum-global-color-red-600);
|
||||||
|
}
|
||||||
|
.status--open {
|
||||||
|
background-color: var(--spectrum-global-color-green-600);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,106 +0,0 @@
|
||||||
<script>
|
|
||||||
import { apps } from "stores/portal"
|
|
||||||
import { gradient } from "actions"
|
|
||||||
import {
|
|
||||||
Heading,
|
|
||||||
Button,
|
|
||||||
Icon,
|
|
||||||
ActionMenu,
|
|
||||||
MenuItem,
|
|
||||||
Link,
|
|
||||||
} from "@budibase/bbui"
|
|
||||||
import { goto, url } from "@roxi/routify"
|
|
||||||
|
|
||||||
export let exportApp
|
|
||||||
|
|
||||||
const openApp = app => {
|
|
||||||
$goto(`../../app/${app._id}`)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if $apps.length}
|
|
||||||
<div class="appTable">
|
|
||||||
{#each $apps as app}
|
|
||||||
<div class="title">
|
|
||||||
<div class="preview" use:gradient />
|
|
||||||
<Link href={$url(`../../app/${app._id}`)}>
|
|
||||||
<Heading size="XS">
|
|
||||||
{app.name}
|
|
||||||
</Heading>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
Edited {Math.round(Math.random() * 10 + 1)} months ago
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{#if Math.random() < 0.33}
|
|
||||||
<div class="status status--open" />
|
|
||||||
Open
|
|
||||||
{:else if Math.random() < 0.33}
|
|
||||||
<div class="status status--locked-other" />
|
|
||||||
Locked by Will Wheaton
|
|
||||||
{:else}
|
|
||||||
<div class="status status--locked-you" />
|
|
||||||
Locked by you
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Button on:click={() => openApp(app)} size="S" secondary>Open</Button>
|
|
||||||
<ActionMenu align="right">
|
|
||||||
<Icon hoverable slot="control" name="More" />
|
|
||||||
<MenuItem on:click={() => exportApp(app)} icon="Download">
|
|
||||||
Export
|
|
||||||
</MenuItem>
|
|
||||||
</ActionMenu>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.appTable {
|
|
||||||
display: grid;
|
|
||||||
grid-template-rows: auto;
|
|
||||||
grid-template-columns: 1fr 1fr 1fr auto;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.appTable > div {
|
|
||||||
border-bottom: var(--border-light);
|
|
||||||
height: 70px;
|
|
||||||
display: grid;
|
|
||||||
align-items: center;
|
|
||||||
gap: var(--spacing-xl);
|
|
||||||
grid-template-columns: auto 1fr;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
padding: 0 var(--spacing-s);
|
|
||||||
}
|
|
||||||
.preview {
|
|
||||||
height: 40px;
|
|
||||||
width: 40px;
|
|
||||||
border-radius: var(--border-radius-s);
|
|
||||||
}
|
|
||||||
.title :global(a) {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.title :global(h1:hover) {
|
|
||||||
color: var(--spectrum-global-color-blue-600);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: color 130ms ease;
|
|
||||||
}
|
|
||||||
.status {
|
|
||||||
height: 10px;
|
|
||||||
width: 10px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
.status--locked-you {
|
|
||||||
background-color: var(--spectrum-global-color-orange-600);
|
|
||||||
}
|
|
||||||
.status--locked-other {
|
|
||||||
background-color: var(--spectrum-global-color-red-600);
|
|
||||||
}
|
|
||||||
.status--open {
|
|
||||||
background-color: var(--spectrum-global-color-green-600);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -14,7 +14,7 @@
|
||||||
import { post } from "builderStore/api"
|
import { post } from "builderStore/api"
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { capitalise } from "../../helpers"
|
import { capitalise } from "helpers"
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
|
|
||||||
export let template
|
export let template
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
<script>
|
|
||||||
export let step, done, active
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="container" class:active class:done>
|
|
||||||
<div class="circle" class:active class:done>
|
|
||||||
{#if done}
|
|
||||||
<svg
|
|
||||||
width="12"
|
|
||||||
height="10"
|
|
||||||
viewBox="0 0 12 10"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
d="M10.1212 0.319527C10.327 0.115582 10.6047 0.000803464 10.8944
|
|
||||||
4.20219e-06C11.1841 -0.00079506 11.4624 0.11245 11.6693
|
|
||||||
0.315256C11.8762 0.518062 11.9949 0.794134 11.9998 1.08379C12.0048
|
|
||||||
1.37344 11.8955 1.65339 11.6957 1.86313L5.82705 9.19893C5.72619
|
|
||||||
9.30757 5.60445 9.39475 5.46913 9.45527C5.3338 9.51578 5.18766 9.54839
|
|
||||||
5.03944 9.55113C4.89123 9.55388 4.74398 9.52671 4.60651
|
|
||||||
9.47124C4.46903 9.41578 4.34416 9.33316 4.23934 9.22833L0.350925
|
|
||||||
5.33845C0.242598 5.23751 0.155712 5.11578 0.0954499 4.98054C0.0351876
|
|
||||||
4.84529 0.00278364 4.69929 0.00017159 4.55124C-0.00244046 4.4032
|
|
||||||
0.024793 4.25615 0.0802466 4.11886C0.1357 3.98157 0.218238 3.85685
|
|
||||||
0.322937 3.75215C0.427636 3.64746 0.55235 3.56492 0.68964
|
|
||||||
3.50946C0.82693 3.45401 0.973983 3.42678 1.12203 3.42939C1.27007 3.432
|
|
||||||
1.41607 3.46441 1.55132 3.52467C1.68657 3.58493 1.80829 3.67182
|
|
||||||
1.90923 3.78014L4.98762 6.85706L10.0933 0.35187C10.1024 0.340482
|
|
||||||
10.1122 0.329679 10.1227 0.319527H10.1212Z"
|
|
||||||
fill="var(--background)"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
{:else}{step}{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.container::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: -30px;
|
|
||||||
width: 1px;
|
|
||||||
height: 30px;
|
|
||||||
background: var(--grey-5);
|
|
||||||
}
|
|
||||||
.container:first-child::before {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
position: relative;
|
|
||||||
height: 45px;
|
|
||||||
display: grid;
|
|
||||||
place-items: center;
|
|
||||||
}
|
|
||||||
.container.active {
|
|
||||||
box-shadow: inset 3px 0 0 0 var(--blue);
|
|
||||||
}
|
|
||||||
.circle.active {
|
|
||||||
background: var(--blue);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
.circle.done {
|
|
||||||
background: var(--grey-5);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
.circle {
|
|
||||||
color: var(--grey-5);
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
display: grid;
|
|
||||||
place-items: center;
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 1px solid var(--grey-5);
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,121 +0,0 @@
|
||||||
<script>
|
|
||||||
import { Label, Heading, Input, notifications } from "@budibase/bbui"
|
|
||||||
|
|
||||||
const BYTES_IN_MB = 1000000
|
|
||||||
const FILE_SIZE_LIMIT = BYTES_IN_MB * 5
|
|
||||||
|
|
||||||
export let template
|
|
||||||
export let values
|
|
||||||
export let errors
|
|
||||||
export let touched
|
|
||||||
|
|
||||||
let blurred = { appName: false }
|
|
||||||
let file
|
|
||||||
|
|
||||||
function handleFile(evt) {
|
|
||||||
const fileArray = Array.from(evt.target.files)
|
|
||||||
if (fileArray.some(file => file.size >= FILE_SIZE_LIMIT)) {
|
|
||||||
notifications.error(
|
|
||||||
`Files cannot exceed ${
|
|
||||||
FILE_SIZE_LIMIT / BYTES_IN_MB
|
|
||||||
}MB. Please try again with smaller files.`
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
file = evt.target.files[0]
|
|
||||||
template.file = file
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
{#if template?.fromFile}
|
|
||||||
<Heading size="L">Import your Web App</Heading>
|
|
||||||
{:else}
|
|
||||||
<Heading size="L">Create your Web App</Heading>
|
|
||||||
{/if}
|
|
||||||
{#if template?.fromFile}
|
|
||||||
<div class="template">
|
|
||||||
<Label extraSmall grey>Import File</Label>
|
|
||||||
<div class="dropzone">
|
|
||||||
<input
|
|
||||||
id="file-upload"
|
|
||||||
accept=".txt"
|
|
||||||
type="file"
|
|
||||||
on:change={handleFile}
|
|
||||||
/>
|
|
||||||
<label for="file-upload" class:uploaded={file}>
|
|
||||||
{#if file}{file.name}{:else}Import{/if}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{:else if template}
|
|
||||||
<div class="template">
|
|
||||||
<Label extraSmall grey>Selected Template</Label>
|
|
||||||
<Heading size="S">{template.name}</Heading>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<Input
|
|
||||||
on:change={() => ($touched.applicationName = true)}
|
|
||||||
bind:value={$values.applicationName}
|
|
||||||
label="Web App Name"
|
|
||||||
placeholder="Enter name of your web application"
|
|
||||||
error={$touched.applicationName && $errors.applicationName}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.container {
|
|
||||||
display: grid;
|
|
||||||
grid-gap: var(--spacing-xl);
|
|
||||||
margin-top: var(--spacing-xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
.template :global(label) {
|
|
||||||
/* Fix layout due to LH 0 on heading */
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropzone {
|
|
||||||
text-align: center;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
border-radius: 10px;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uploaded {
|
|
||||||
color: var(--blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="file"] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
font-family: var(--font-sans);
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: 500;
|
|
||||||
box-sizing: border-box;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: var(--border-radius-s);
|
|
||||||
color: var(--ink);
|
|
||||||
padding: var(--spacing-m) var(--spacing-l);
|
|
||||||
transition: all 0.2s ease 0s;
|
|
||||||
display: inline-flex;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
min-width: auto;
|
|
||||||
outline: none;
|
|
||||||
font-feature-settings: "case" 1, "rlig" 1, "calt" 0;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
user-select: none;
|
|
||||||
flex-shrink: 0;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
line-height: normal;
|
|
||||||
border: var(--border-transparent);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,29 +0,0 @@
|
||||||
<script>
|
|
||||||
import { Select, Heading } from "@budibase/bbui"
|
|
||||||
|
|
||||||
export let values
|
|
||||||
export let errors
|
|
||||||
export let touched
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<Heading size="L">What's your role for this app?</Heading>
|
|
||||||
<Select
|
|
||||||
bind:value={$values.roleId}
|
|
||||||
label="Role"
|
|
||||||
options={[
|
|
||||||
{ label: "Admin", value: "ADMIN" },
|
|
||||||
{ label: "Power User", value: "POWER_USER" },
|
|
||||||
]}
|
|
||||||
getOptionLabel={option => option.label}
|
|
||||||
getOptionValue={option => option.value}
|
|
||||||
error={$errors.roleId}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.container {
|
|
||||||
display: grid;
|
|
||||||
grid-gap: var(--spacing-xl);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,2 +0,0 @@
|
||||||
export { default as Info } from "./Info.svelte"
|
|
||||||
export { default as User } from "./User.svelte"
|
|
|
@ -11,18 +11,22 @@
|
||||||
Page,
|
Page,
|
||||||
notifications,
|
notifications,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import AppGridView from "components/start/AppGridView.svelte"
|
|
||||||
import AppTableView from "components/start/AppTableView.svelte"
|
|
||||||
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
||||||
import api from "builderStore/api"
|
import api, { del } from "builderStore/api"
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { apps } from "stores/portal"
|
import { apps } from "stores/portal"
|
||||||
import download from "downloadjs"
|
import download from "downloadjs"
|
||||||
|
import { goto } from "@roxi/routify"
|
||||||
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||||
|
import AppCard from "components/start/AppCard.svelte"
|
||||||
|
import AppRow from "components/start/AppRow.svelte"
|
||||||
|
|
||||||
let layout = "grid"
|
let layout = "grid"
|
||||||
let modal
|
|
||||||
let template
|
let template
|
||||||
|
let appToDelete
|
||||||
|
let creationModal
|
||||||
|
let deletionModal
|
||||||
|
|
||||||
const checkKeys = async () => {
|
const checkKeys = async () => {
|
||||||
const response = await api.get(`/api/keys/`)
|
const response = await api.get(`/api/keys/`)
|
||||||
|
@ -34,7 +38,11 @@
|
||||||
|
|
||||||
const initiateAppImport = () => {
|
const initiateAppImport = () => {
|
||||||
template = { fromFile: true }
|
template = { fromFile: true }
|
||||||
modal.show()
|
creationModal.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
const openApp = app => {
|
||||||
|
$goto(`../../app/${app._id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const exportApp = app => {
|
const exportApp = app => {
|
||||||
|
@ -51,6 +59,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deleteApp = app => {
|
||||||
|
appToDelete = app
|
||||||
|
deletionModal.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmDeleteApp = async () => {
|
||||||
|
if (!appToDelete) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await del(`/api/applications/${appToDelete?._id}`)
|
||||||
|
await apps.load()
|
||||||
|
appToDelete = null
|
||||||
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
checkKeys()
|
checkKeys()
|
||||||
apps.load()
|
apps.load()
|
||||||
|
@ -63,7 +85,7 @@
|
||||||
<Heading>Apps</Heading>
|
<Heading>Apps</Heading>
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<Button secondary on:click={initiateAppImport}>Import app</Button>
|
<Button secondary on:click={initiateAppImport}>Import app</Button>
|
||||||
<Button cta on:click={modal.show}>Create new app</Button>
|
<Button cta on:click={creationModal.show}>Create new app</Button>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter">
|
<div class="filter">
|
||||||
|
@ -86,24 +108,42 @@
|
||||||
</ActionGroup>
|
</ActionGroup>
|
||||||
</div>
|
</div>
|
||||||
{#if $apps.length}
|
{#if $apps.length}
|
||||||
{#if layout === "grid"}
|
<div
|
||||||
<AppGridView {exportApp} />
|
class:appGrid={layout === "grid"}
|
||||||
{:else}
|
class:appTable={layout === "table"}
|
||||||
<AppTableView {exportApp} />
|
>
|
||||||
{/if}
|
{#each $apps as app, idx}
|
||||||
|
<svelte:component
|
||||||
|
this={layout === "grid" ? AppCard : AppRow}
|
||||||
|
{app}
|
||||||
|
{openApp}
|
||||||
|
{exportApp}
|
||||||
|
{deleteApp}
|
||||||
|
last={idx === $apps.length - 1}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div>No apps.</div>
|
<div>No apps.</div>
|
||||||
{/if}
|
{/if}
|
||||||
</Layout>
|
</Layout>
|
||||||
</Page>
|
</Page>
|
||||||
<Modal
|
<Modal
|
||||||
bind:this={modal}
|
bind:this={creationModal}
|
||||||
padding={false}
|
padding={false}
|
||||||
width="600px"
|
width="600px"
|
||||||
on:hide={() => (template = null)}
|
on:hide={() => (template = null)}
|
||||||
>
|
>
|
||||||
<CreateAppModal {template} />
|
<CreateAppModal {template} />
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<ConfirmDialog
|
||||||
|
bind:this={deletionModal}
|
||||||
|
title="Confirm deletion"
|
||||||
|
okText="Delete app"
|
||||||
|
onOk={confirmDeleteApp}
|
||||||
|
>
|
||||||
|
Are you sure you want to delete the app <b>{appToDelete?.name}</b>?
|
||||||
|
</ConfirmDialog>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.title,
|
.title,
|
||||||
|
@ -117,4 +157,30 @@
|
||||||
.select {
|
.select {
|
||||||
width: 110px;
|
width: 110px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.appGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 50px;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
|
}
|
||||||
|
.appTable {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr auto;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.appTable :global(> div) {
|
||||||
|
height: 70px;
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-xl);
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
padding: 0 var(--spacing-s);
|
||||||
|
}
|
||||||
|
.appTable :global(> div:not(.last)) {
|
||||||
|
border-bottom: var(--border-light);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue