Adding in main portal page automation error notification.

This commit is contained in:
mike12345567 2022-06-21 00:02:22 +01:00
parent e9d3a1e92f
commit 2ff853c917
8 changed files with 114 additions and 18 deletions

View File

@ -1,15 +1,20 @@
<script> <script>
import { ActionButton } from "../"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
export let type = "info" export let type = "info"
export let icon = "Info" export let icon = "Info"
export let message = "" export let message = ""
export let dismissable = false export let dismissable = false
export let actionMessage = null
export let action = null
export let wide = false
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
</script> </script>
<div class="spectrum-Toast spectrum-Toast--{type}"> <div class="spectrum-Toast spectrum-Toast--{type}" class:wide>
{#if icon} {#if icon}
<svg <svg
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Toast-typeIcon" class="spectrum-Icon spectrum-Icon--sizeM spectrum-Toast-typeIcon"
@ -19,8 +24,13 @@
<use xlink:href="#spectrum-icon-18-{icon}" /> <use xlink:href="#spectrum-icon-18-{icon}" />
</svg> </svg>
{/if} {/if}
<div class="spectrum-Toast-body"> <div class="spectrum-Toast-body" class:actionBody={!!action}>
<div class="spectrum-Toast-content">{message || ""}</div> <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> </div>
{#if dismissable} {#if dismissable}
<div class="spectrum-Toast-buttons"> <div class="spectrum-Toast-buttons">
@ -46,4 +56,15 @@
.spectrum-Toast { .spectrum-Toast {
pointer-events: all; pointer-events: all;
} }
.wide {
width: 100%;
}
.actionBody {
justify-content: space-between;
display: flex;
width: 100%;
align-items: center;
}
</style> </style>

View File

@ -8,13 +8,15 @@
<Portal target=".modal-container"> <Portal target=".modal-container">
<div class="notifications"> <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 }}> <div transition:fly={{ y: -30 }}>
<Notification <Notification
{type} {type}
{icon} {icon}
{message} {message}
{dismissable} {dismissable}
{action}
{wide}
on:dismiss={() => notifications.dismiss(id)} on:dismiss={() => notifications.dismiss(id)}
/> />
</div> </div>

View File

@ -20,7 +20,16 @@ export const createNotificationStore = () => {
setTimeout(() => (block = false), timeout) 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) { if (block) {
return return
} }
@ -28,7 +37,15 @@ export const createNotificationStore = () => {
_notifications.update(state => { _notifications.update(state => {
return [ return [
...state, ...state,
{ id: _id, type, message, icon, dismissable: !autoDismiss }, {
id: _id,
type,
message,
icon,
dismissable: !autoDismiss,
action,
wide,
},
] ]
}) })
if (autoDismiss) { if (autoDismiss) {
@ -50,10 +67,11 @@ export const createNotificationStore = () => {
return { return {
subscribe, subscribe,
send, send,
info: msg => send(msg, "info", "Info"), info: msg => send(msg, { type: "info", icon: "Info" }),
error: msg => send(msg, "error", "Alert", false), error: msg =>
warning: msg => send(msg, "warning", "Alert"), send(msg, { type: "error", icon: "Alert", autoDismiss: false }),
success: msg => send(msg, "success", "CheckmarkCircle"), warning: msg => send(msg, { type: "warning", icon: "Alert" }),
success: msg => send(msg, { type: "success", icon: "CheckmarkCircle" }),
blockNotifications, blockNotifications,
dismiss: dismissNotification, dismiss: dismissNotification,
} }

View File

@ -129,6 +129,7 @@ const automationActions = store => ({
page, page,
}) })
}, },
clearLogErrors: async () => {},
addTestDataToAutomation: data => { addTestDataToAutomation: data => {
store.update(state => { store.update(state => {
state.selectedAutomation.addTestData(data) state.selectedAutomation.addTestData(data)

View File

@ -4,10 +4,15 @@
import DateTimeRenderer from "components/common/renderers/DateTimeRenderer.svelte" import DateTimeRenderer from "components/common/renderers/DateTimeRenderer.svelte"
import TestDisplay from "components/automation/AutomationBuilder/TestDisplay.svelte" import TestDisplay from "components/automation/AutomationBuilder/TestDisplay.svelte"
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { automationStore } from "builderStore"
export let history export let history
export let appId export let appId
export let close export let close
$: exists = $automationStore.automations?.find(
auto => auto._id === history?.automationId
)
</script> </script>
{#if history} {#if history}
@ -28,6 +33,7 @@
<div>{history.automationName}</div> <div>{history.automationName}</div>
</div> </div>
<div> <div>
{#if exists}
<ActionButton <ActionButton
icon="Edit" icon="Edit"
fullWidth={false} fullWidth={false}
@ -35,6 +41,7 @@
$goto(`../../../app/${appId}/automate/${history.automationId}`)} $goto(`../../../app/${appId}/automate/${history.automationId}`)}
>Edit automation</ActionButton >Edit automation</ActionButton
> >
{/if}
</div> </div>
</Layout> </Layout>
<div class="bottom"> <div class="bottom">

View File

@ -126,7 +126,7 @@
/> />
</div> </div>
</div> </div>
{#if runHistory} {#if runHistory && runHistory.length}
<Table <Table
on:click={viewDetails} on:click={viewDetails}
schema={runHistorySchema} schema={runHistorySchema}

View File

@ -7,6 +7,7 @@
Modal, Modal,
Page, Page,
notifications, notifications,
Notification,
Body, Body,
Search, Search,
} from "@budibase/bbui" } from "@budibase/bbui"
@ -37,6 +38,7 @@
let searchTerm = "" let searchTerm = ""
let cloud = $admin.cloud let cloud = $admin.cloud
let creatingFromTemplate = false let creatingFromTemplate = false
let automationErrors
const resolveWelcomeMessage = (auth, apps) => { const resolveWelcomeMessage = (auth, apps) => {
const userWelcome = auth?.user?.firstName const userWelcome = auth?.user?.firstName
@ -59,7 +61,8 @@
) )
$: lockedApps = filteredApps.filter(app => app?.lockedYou || app?.lockedOther) $: 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 enrichApps = (apps, user, sortBy) => {
const enrichedApps = apps.map(app => ({ 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 = () => { const initiateAppCreation = () => {
if ($apps?.length) { if ($apps?.length) {
$goto("/builder/portal/apps/create") $goto("/builder/portal/apps/create")
@ -208,6 +238,19 @@
<Page wide> <Page wide>
<Layout noPadding gap="M"> <Layout noPadding gap="M">
{#if loaded} {#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="title">
<div class="welcome"> <div class="welcome">
<Layout noPadding gap="XS"> <Layout noPadding gap="XS">

View File

@ -188,6 +188,10 @@
}) })
onMount(async () => { onMount(async () => {
const params = new URLSearchParams(window.location.search)
if (params.get("tab")) {
selectedTab = params.get("tab")
}
try { try {
if (!apps.length) { if (!apps.length) {
await apps.load() await apps.load()