Minor UI updates for the create app modal. A spinner has been added to the modal confirmation UX. The app name is pre-populated using the app name. The app URL can no longer be null
This commit is contained in:
parent
768f9e8679
commit
cc0280ca0c
5 changed files with 66 additions and 43 deletions
|
@ -5,6 +5,7 @@
|
|||
import Divider from "../Divider/Divider.svelte"
|
||||
import Icon from "../Icon/Icon.svelte"
|
||||
import Context from "../context"
|
||||
import ProgressCircle from "../ProgressCircle/ProgressCircle.svelte"
|
||||
|
||||
export let title = undefined
|
||||
export let size = "S"
|
||||
|
@ -102,15 +103,22 @@
|
|||
<Button group secondary on:click={close}>{cancelText}</Button>
|
||||
{/if}
|
||||
{#if showConfirmButton}
|
||||
<Button
|
||||
group
|
||||
cta
|
||||
{...$$restProps}
|
||||
disabled={confirmDisabled}
|
||||
on:click={confirm}
|
||||
>
|
||||
{confirmText}
|
||||
</Button>
|
||||
<span class="confirm-wrap">
|
||||
<Button
|
||||
group
|
||||
cta
|
||||
{...$$restProps}
|
||||
disabled={confirmDisabled}
|
||||
on:click={confirm}
|
||||
>
|
||||
{#if loading}
|
||||
<ProgressCircle overBackground={true} size="S" />
|
||||
{/if}
|
||||
{#if !loading}
|
||||
{confirmText}
|
||||
{/if}
|
||||
</Button>
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -169,4 +177,8 @@
|
|||
.spectrum-Dialog-buttonGroup {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.confirm-wrap :global(.spectrum-Button-label) {
|
||||
display: contents;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -13,18 +13,20 @@
|
|||
|
||||
export let template
|
||||
|
||||
let creating = false
|
||||
|
||||
const values = writable({ name: "", url: null })
|
||||
const validation = createValidationStore()
|
||||
$: validation.check($values)
|
||||
|
||||
onMount(async () => {
|
||||
$values.url = resolveAppUrl(template, $values.name, $values.url)
|
||||
$values.name = resolveAppName(template, $values.name)
|
||||
nameToUrl($values.name)
|
||||
await setupValidation()
|
||||
})
|
||||
|
||||
$: appUrl = `${window.location.origin}${
|
||||
$values.url ? $values.url : `/${resolveAppUrl(template, $values.name)}`
|
||||
$values.url ? $values.url : `${resolveAppUrl(template, $values.name)}`
|
||||
}`
|
||||
|
||||
const resolveAppUrl = (template, name) => {
|
||||
|
@ -39,7 +41,19 @@
|
|||
if (template && !name) {
|
||||
return template.name
|
||||
}
|
||||
return name.trim()
|
||||
return name ? name.trim() : null
|
||||
}
|
||||
|
||||
const tidyUrl = url => {
|
||||
if (url && !url.startsWith("/")) {
|
||||
url = `/${url}`
|
||||
}
|
||||
$values.url = url === "" ? null : url
|
||||
}
|
||||
|
||||
const nameToUrl = appName => {
|
||||
let resolvedUrl = resolveAppUrl(template, appName)
|
||||
tidyUrl(resolvedUrl)
|
||||
}
|
||||
|
||||
const setupValidation = async () => {
|
||||
|
@ -52,6 +66,8 @@
|
|||
}
|
||||
|
||||
async function createNewApp() {
|
||||
creating = true
|
||||
|
||||
try {
|
||||
// Create form data to create app
|
||||
let data = new FormData()
|
||||
|
@ -86,17 +102,11 @@
|
|||
await auth.setInitInfo({})
|
||||
$goto(`/builder/app/${createdApp.instance._id}`)
|
||||
} catch (error) {
|
||||
creating = false
|
||||
console.error(error)
|
||||
notifications.error("Error creating app")
|
||||
}
|
||||
}
|
||||
|
||||
// auto add slash to url
|
||||
$: {
|
||||
if ($values.url && !$values.url.startsWith("/")) {
|
||||
$values.url = `/${$values.url}`
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<ModalContent
|
||||
|
@ -128,41 +138,38 @@
|
|||
{/if}
|
||||
<Input
|
||||
bind:value={$values.name}
|
||||
disabled={creating}
|
||||
error={$validation.touched.name && $validation.errors.name}
|
||||
on:blur={() => ($validation.touched.name = true)}
|
||||
on:change={nameToUrl($values.name)}
|
||||
label="Name"
|
||||
placeholder={$auth.user.firstName
|
||||
placeholder={$auth.user?.firstName
|
||||
? `${$auth.user.firstName}s app`
|
||||
: "My app"}
|
||||
/>
|
||||
<span>
|
||||
<Input
|
||||
bind:value={$values.url}
|
||||
disabled={creating}
|
||||
error={$validation.touched.url && $validation.errors.url}
|
||||
on:blur={() => ($validation.touched.url = true)}
|
||||
on:change={tidyUrl($values.url)}
|
||||
label="URL"
|
||||
placeholder={$values.url
|
||||
? $values.url
|
||||
: `/${resolveAppUrl(template, $values.name)}`}
|
||||
/>
|
||||
{#if $values.name}
|
||||
<div class="app-server-wrap" title={appUrl}>
|
||||
<span class="app-server-prefix">
|
||||
{window.location.origin}
|
||||
</span>
|
||||
{$values.url
|
||||
? $values.url
|
||||
: `/${resolveAppUrl(template, $values.name)}`}
|
||||
{#if $values.url && $values.url !== "" && !$validation.errors.url}
|
||||
<div class="app-server" title={appUrl}>
|
||||
{`${window.location.origin}${$values.url}`}
|
||||
</div>
|
||||
{/if}
|
||||
</span>
|
||||
</ModalContent>
|
||||
|
||||
<style>
|
||||
.app-server-prefix {
|
||||
color: var(--spectrum-global-color-gray-500);
|
||||
}
|
||||
.app-server-wrap {
|
||||
.app-server {
|
||||
color: var(--spectrum-global-color-gray-600);
|
||||
margin-top: 10px;
|
||||
width: 320px;
|
||||
white-space: nowrap;
|
||||
|
|
|
@ -35,13 +35,14 @@ export const url = (validation, { apps, currentApp } = { apps: [] }) => {
|
|||
validation.addValidator(
|
||||
"url",
|
||||
string()
|
||||
.trim()
|
||||
.nullable()
|
||||
.matches(APP_URL_REGEX, "App URL must not contain spaces")
|
||||
.required("Your application must have a url")
|
||||
.matches(APP_URL_REGEX, "Please enter a valid url")
|
||||
.test(
|
||||
"non-existing-app-url",
|
||||
"Another app with the same URL already exists",
|
||||
value => {
|
||||
// url is nullable
|
||||
if (!value) {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
Body,
|
||||
Modal,
|
||||
Divider,
|
||||
Link,
|
||||
} from "@budibase/bbui"
|
||||
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
||||
import TemplateDisplay from "components/common/TemplateDisplay.svelte"
|
||||
|
@ -60,14 +61,15 @@
|
|||
<Page wide>
|
||||
<Layout noPadding gap="XL">
|
||||
<span>
|
||||
<Button
|
||||
primary
|
||||
<Link
|
||||
quiet
|
||||
secondary
|
||||
on:click={() => {
|
||||
$goto("../")
|
||||
}}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
< Back
|
||||
</Link>
|
||||
</span>
|
||||
|
||||
<div class="title">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { goto } from "@roxi/routify"
|
||||
import { Layout, Page, notifications, Button } from "@budibase/bbui"
|
||||
import { Layout, Page, notifications, Link } from "@budibase/bbui"
|
||||
import TemplateDisplay from "components/common/TemplateDisplay.svelte"
|
||||
import { onMount } from "svelte"
|
||||
import { templates } from "stores/portal"
|
||||
|
@ -25,14 +25,15 @@
|
|||
<Page wide>
|
||||
<Layout noPadding gap="XL">
|
||||
<span>
|
||||
<Button
|
||||
primary
|
||||
<Link
|
||||
quiet
|
||||
secondary
|
||||
on:click={() => {
|
||||
$goto("../")
|
||||
}}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
< Back
|
||||
</Link>
|
||||
</span>
|
||||
{#if loaded && $templates?.length}
|
||||
<TemplateDisplay templates={$templates} />
|
||||
|
|
Loading…
Reference in a new issue