Adding in main portal page automation error notification.
This commit is contained in:
parent
e9d3a1e92f
commit
2ff853c917
|
@ -1,15 +1,20 @@
|
|||
<script>
|
||||
import { ActionButton } from "../"
|
||||
|
||||
import { createEventDispatcher } from "svelte"
|
||||
|
||||
export let type = "info"
|
||||
export let icon = "Info"
|
||||
export let message = ""
|
||||
export let dismissable = false
|
||||
export let actionMessage = null
|
||||
export let action = null
|
||||
export let wide = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<div class="spectrum-Toast spectrum-Toast--{type}">
|
||||
<div class="spectrum-Toast spectrum-Toast--{type}" class:wide>
|
||||
{#if icon}
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Toast-typeIcon"
|
||||
|
@ -19,8 +24,13 @@
|
|||
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||
</svg>
|
||||
{/if}
|
||||
<div class="spectrum-Toast-body">
|
||||
<div class="spectrum-Toast-body" class:actionBody={!!action}>
|
||||
<div class="spectrum-Toast-content">{message || ""}</div>
|
||||
{#if action}
|
||||
<ActionButton quiet emphasized on:click={action}>
|
||||
<div style="color: white; font-weight: 600;">{actionMessage}</div>
|
||||
</ActionButton>
|
||||
{/if}
|
||||
</div>
|
||||
{#if dismissable}
|
||||
<div class="spectrum-Toast-buttons">
|
||||
|
@ -46,4 +56,15 @@
|
|||
.spectrum-Toast {
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.wide {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.actionBody {
|
||||
justify-content: space-between;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -8,13 +8,15 @@
|
|||
|
||||
<Portal target=".modal-container">
|
||||
<div class="notifications">
|
||||
{#each $notifications as { type, icon, message, id, dismissable } (id)}
|
||||
{#each $notifications as { type, icon, message, id, dismissable, action, wide } (id)}
|
||||
<div transition:fly={{ y: -30 }}>
|
||||
<Notification
|
||||
{type}
|
||||
{icon}
|
||||
{message}
|
||||
{dismissable}
|
||||
{action}
|
||||
{wide}
|
||||
on:dismiss={() => notifications.dismiss(id)}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -20,7 +20,16 @@ export const createNotificationStore = () => {
|
|||
setTimeout(() => (block = false), timeout)
|
||||
}
|
||||
|
||||
const send = (message, type = "default", icon = "", autoDismiss = true) => {
|
||||
const send = (
|
||||
message,
|
||||
{
|
||||
type = "default",
|
||||
icon = "",
|
||||
autoDismiss = true,
|
||||
action = null,
|
||||
wide = false,
|
||||
}
|
||||
) => {
|
||||
if (block) {
|
||||
return
|
||||
}
|
||||
|
@ -28,7 +37,15 @@ export const createNotificationStore = () => {
|
|||
_notifications.update(state => {
|
||||
return [
|
||||
...state,
|
||||
{ id: _id, type, message, icon, dismissable: !autoDismiss },
|
||||
{
|
||||
id: _id,
|
||||
type,
|
||||
message,
|
||||
icon,
|
||||
dismissable: !autoDismiss,
|
||||
action,
|
||||
wide,
|
||||
},
|
||||
]
|
||||
})
|
||||
if (autoDismiss) {
|
||||
|
@ -50,10 +67,11 @@ export const createNotificationStore = () => {
|
|||
return {
|
||||
subscribe,
|
||||
send,
|
||||
info: msg => send(msg, "info", "Info"),
|
||||
error: msg => send(msg, "error", "Alert", false),
|
||||
warning: msg => send(msg, "warning", "Alert"),
|
||||
success: msg => send(msg, "success", "CheckmarkCircle"),
|
||||
info: msg => send(msg, { type: "info", icon: "Info" }),
|
||||
error: msg =>
|
||||
send(msg, { type: "error", icon: "Alert", autoDismiss: false }),
|
||||
warning: msg => send(msg, { type: "warning", icon: "Alert" }),
|
||||
success: msg => send(msg, { type: "success", icon: "CheckmarkCircle" }),
|
||||
blockNotifications,
|
||||
dismiss: dismissNotification,
|
||||
}
|
||||
|
|
|
@ -129,6 +129,7 @@ const automationActions = store => ({
|
|||
page,
|
||||
})
|
||||
},
|
||||
clearLogErrors: async () => {},
|
||||
addTestDataToAutomation: data => {
|
||||
store.update(state => {
|
||||
state.selectedAutomation.addTestData(data)
|
||||
|
|
|
@ -4,10 +4,15 @@
|
|||
import DateTimeRenderer from "components/common/renderers/DateTimeRenderer.svelte"
|
||||
import TestDisplay from "components/automation/AutomationBuilder/TestDisplay.svelte"
|
||||
import { goto } from "@roxi/routify"
|
||||
import { automationStore } from "builderStore"
|
||||
|
||||
export let history
|
||||
export let appId
|
||||
export let close
|
||||
|
||||
$: exists = $automationStore.automations?.find(
|
||||
auto => auto._id === history?.automationId
|
||||
)
|
||||
</script>
|
||||
|
||||
{#if history}
|
||||
|
@ -28,13 +33,15 @@
|
|||
<div>{history.automationName}</div>
|
||||
</div>
|
||||
<div>
|
||||
<ActionButton
|
||||
icon="Edit"
|
||||
fullWidth={false}
|
||||
on:click={() =>
|
||||
$goto(`../../../app/${appId}/automate/${history.automationId}`)}
|
||||
>Edit automation</ActionButton
|
||||
>
|
||||
{#if exists}
|
||||
<ActionButton
|
||||
icon="Edit"
|
||||
fullWidth={false}
|
||||
on:click={() =>
|
||||
$goto(`../../../app/${appId}/automate/${history.automationId}`)}
|
||||
>Edit automation</ActionButton
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</Layout>
|
||||
<div class="bottom">
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
{#if runHistory}
|
||||
{#if runHistory && runHistory.length}
|
||||
<Table
|
||||
on:click={viewDetails}
|
||||
schema={runHistorySchema}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
Modal,
|
||||
Page,
|
||||
notifications,
|
||||
Notification,
|
||||
Body,
|
||||
Search,
|
||||
} from "@budibase/bbui"
|
||||
|
@ -37,6 +38,7 @@
|
|||
let searchTerm = ""
|
||||
let cloud = $admin.cloud
|
||||
let creatingFromTemplate = false
|
||||
let automationErrors
|
||||
|
||||
const resolveWelcomeMessage = (auth, apps) => {
|
||||
const userWelcome = auth?.user?.firstName
|
||||
|
@ -59,7 +61,8 @@
|
|||
)
|
||||
|
||||
$: lockedApps = filteredApps.filter(app => app?.lockedYou || app?.lockedOther)
|
||||
$: unlocked = lockedApps?.length == 0
|
||||
$: unlocked = lockedApps?.length === 0
|
||||
$: automationErrors = getAutomationErrors(enrichedApps)
|
||||
|
||||
const enrichApps = (apps, user, sortBy) => {
|
||||
const enrichedApps = apps.map(app => ({
|
||||
|
@ -89,6 +92,33 @@
|
|||
}
|
||||
}
|
||||
|
||||
const getAutomationErrors = apps => {
|
||||
const automationErrors = {}
|
||||
for (let app of apps) {
|
||||
if (app.automationErrors) {
|
||||
automationErrors[app.devId] = app.automationErrors
|
||||
}
|
||||
}
|
||||
return automationErrors
|
||||
}
|
||||
|
||||
const goToAutomationError = appId => {
|
||||
const params = new URLSearchParams({ tab: "Automation History" })
|
||||
$goto(`../overview/${appId}?${params.toString()}`)
|
||||
}
|
||||
|
||||
const errorCount = appId => {
|
||||
return Object.values(automationErrors[appId]).reduce(
|
||||
(prev, next) => prev + next,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
const automationErrorMessage = appId => {
|
||||
const app = enrichedApps.find(app => app.devId === appId)
|
||||
return `${app.name} - Automation error (${errorCount(appId)})`
|
||||
}
|
||||
|
||||
const initiateAppCreation = () => {
|
||||
if ($apps?.length) {
|
||||
$goto("/builder/portal/apps/create")
|
||||
|
@ -208,6 +238,19 @@
|
|||
<Page wide>
|
||||
<Layout noPadding gap="M">
|
||||
{#if loaded}
|
||||
{#if automationErrors}
|
||||
{#each Object.keys(automationErrors) as appId}
|
||||
<Notification
|
||||
wide
|
||||
dismissable
|
||||
action={() => goToAutomationError(appId)}
|
||||
type="error"
|
||||
icon="Alert"
|
||||
actionMessage={errorCount(appId) > 1 ? "View errors" : "View error"}
|
||||
message={automationErrorMessage(appId)}
|
||||
/>
|
||||
{/each}
|
||||
{/if}
|
||||
<div class="title">
|
||||
<div class="welcome">
|
||||
<Layout noPadding gap="XS">
|
||||
|
|
|
@ -188,6 +188,10 @@
|
|||
})
|
||||
|
||||
onMount(async () => {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
if (params.get("tab")) {
|
||||
selectedTab = params.get("tab")
|
||||
}
|
||||
try {
|
||||
if (!apps.length) {
|
||||
await apps.load()
|
||||
|
|
Loading…
Reference in New Issue