moves NotificationDisplay to bbui and converts it to spectrum

This commit is contained in:
Keviin Åberg Kultalahti 2021-04-09 12:02:53 +02:00
parent af983023fb
commit 5a2287ddcb
47 changed files with 200 additions and 206 deletions

View File

@ -38,5 +38,8 @@
"test:e2e:ci": "lerna run cy:ci", "test:e2e:ci": "lerna run cy:ci",
"build:docker": "cd hosting/scripts/linux/ && ./release-to-docker-hub.sh && cd -", "build:docker": "cd hosting/scripts/linux/ && ./release-to-docker-hub.sh && cd -",
"build:docker:staging": "cd hosting/scripts/linux/ && ./release-to-docker-hub.sh staging && cd -" "build:docker:staging": "cd hosting/scripts/linux/ && ./release-to-docker-hub.sh staging && cd -"
},
"dependencies": {
"@spectrum-css/toast": "^3.0.1"
} }
} }

View File

@ -0,0 +1,44 @@
<script>
import "@spectrum-css/toast/dist/index-vars.css"
import Portal from "svelte-portal"
import { flip } from "svelte/animate"
import { fly } from "svelte/transition"
import { notifications } from '../Stores/notifications'
</script>
<Portal target=".modal-container">
<div class="notifications">
{#each $notifications as {type, icon, message, id} (id)}
<div animate:flip transition:fly={{ y: -30 }} class="spectrum-Toast spectrum-Toast--{type} notification-offset">
{#if icon}
<svg class="spectrum-Icon spectrum-Icon--sizeM spectrum-Toast-typeIcon" focusable="false" aria-hidden="true">
<use xlink:href="#spectrum-icon-18-{icon}" />
</svg>
{/if}
<div class="spectrum-Toast-body">
<div class="spectrum-Toast-content">{message}</div>
</div>
</div>
{/each}
</div>
</Portal>
<style>
.notifications {
position: fixed;
top: 10px;
left: 0;
right: 0;
margin: 0 auto;
padding: 0;
z-index: 9999;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
pointer-events: none;
}
.notification-offset {
margin-bottom: 10px;
}
</style>

View File

@ -19,7 +19,7 @@ This custom can be used to display toast messages. It has 5 different methods: `
<View name="danger"> <View name="danger">
<button on:click={() => notifications.danger('This is a danger!')}>Danger</button> <button on:click={() => notifications.error('This is a danger!')}>Danger</button>
</View> </View>
<View name="warning"> <View name="warning">
<button on:click={() => notifications.warning('This is a warning!')}>Warning</button> <button on:click={() => notifications.warning('This is a warning!')}>Warning</button>

View File

@ -1,40 +1,51 @@
import { writable, derived } from "svelte/store" import { writable } from "svelte/store"
const NOTIFICATION_TIMEOUT = 3000 const NOTIFICATION_TIMEOUT = 3000
const createNotificationStore = () => { export const createNotificationStore = () => {
const _notifications = writable([]) const timeoutIds = new Set()
const _notifications = writable([], () => {
const send = (message, type = "default") => {
_notifications.update(state => {
return [...state, { id: id(), type, message }]
})
}
const notifications = derived(_notifications, ($_notifications, set) => {
set($_notifications)
if ($_notifications.length > 0) {
const timeout = setTimeout(() => {
_notifications.update(state => {
state.shift()
return state
})
set($_notifications)
}, NOTIFICATION_TIMEOUT)
return () => { return () => {
clearTimeout(timeout) // clear all the timers
} timeoutIds.forEach(timeoutId => {
clearTimeout(timeoutId)
})
_notifications.set([])
} }
}) })
const { subscribe } = notifications let block = false
const blockNotifications = (timeout = 1000) => {
block = true
setTimeout(() => (block = false), timeout)
}
const send = (message, type = "default", icon = "") => {
if (block) {
return
}
let _id = id()
_notifications.update(state => {
return [...state, { id: _id, type, message, icon }]
})
const timeoutId = setTimeout(() => {
_notifications.update(state => {
return state.filter(({ id }) => id !== _id)
})
}, NOTIFICATION_TIMEOUT)
timeoutIds.add(timeoutId)
}
const { subscribe } = _notifications
return { return {
subscribe, subscribe,
send, send,
danger: msg => send(msg, "danger"), info: msg => send(msg, "info", "Info"),
warning: msg => send(msg, "warning"), error: msg => send(msg, "error", "Alert"),
info: msg => send(msg, "info"), warning: msg => send(msg, "warning", "Alert"),
success: msg => send(msg, "success"), success: msg => send(msg, "success", "CheckmarkCircle"),
blockNotifications,
} }
} }

View File

@ -25,6 +25,7 @@ export { default as Label } from "./Styleguide/Label.svelte"
export { default as Close } from "./Button/Close.svelte" export { default as Close } from "./Button/Close.svelte"
export { default as Modal } from "./Modal/Modal.svelte" export { default as Modal } from "./Modal/Modal.svelte"
export { default as ModalContent } from "./Modal/ModalContent.svelte" export { default as ModalContent } from "./Modal/ModalContent.svelte"
export { default as NotificationDisplay } from "./Notification/NotificationDisplay.svelte"
export { default as Spacer } from "./Spacer/Spacer.svelte" export { default as Spacer } from "./Spacer/Spacer.svelte"
export { default as DatePicker } from "./DatePicker/DatePicker.svelte" export { default as DatePicker } from "./DatePicker/DatePicker.svelte"
export { default as Multiselect } from "./Form/Multiselect.svelte" export { default as Multiselect } from "./Form/Multiselect.svelte"
@ -37,4 +38,4 @@ export { default as positionDropdown } from "./Actions/position_dropdown"
export { default as clickOutside } from "./Actions/click_outside" export { default as clickOutside } from "./Actions/click_outside"
// Stores // Stores
export { notifications } from "./Stores/notifications" export { notifications, createNotificationStore } from "./Stores/notifications"

View File

@ -3,7 +3,7 @@
import { Router } from "@roxi/routify" import { Router } from "@roxi/routify"
import { routes } from "../.routify/routes" import { routes } from "../.routify/routes"
import { initialise } from "builderStore" import { initialise } from "builderStore"
import NotificationDisplay from "components/common/Notification/NotificationDisplay.svelte" import { NotificationDisplay } from "@budibase/bbui"
onMount(async () => { onMount(async () => {
await initialise() await initialise()

View File

@ -2,7 +2,7 @@
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { database } from "stores/backend" import { database } from "stores/backend"
import { automationStore } from "builderStore" import { automationStore } from "builderStore"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { Input, ModalContent } from "@budibase/bbui" import { Input, ModalContent } from "@budibase/bbui"
import analytics from "analytics" import analytics from "analytics"
@ -16,7 +16,7 @@
name, name,
instanceId, instanceId,
}) })
notifier.success(`Automation ${name} created.`) notifications.success(`Automation ${name} created.`)
$goto(`./${$automationStore.selectedAutomation.automation._id}`) $goto(`./${$automationStore.selectedAutomation.automation._id}`)
analytics.captureEvent("Automation Created", { name }) analytics.captureEvent("Automation Created", { name })
} }

View File

@ -2,7 +2,7 @@
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { automationStore } from "builderStore" import { automationStore } from "builderStore"
import { database } from "stores/backend" import { database } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { DropdownMenu } from "@budibase/bbui" import { DropdownMenu } from "@budibase/bbui"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns" import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
@ -24,7 +24,7 @@
instanceId, instanceId,
automation, automation,
}) })
notifier.success("Automation deleted.") notifications.success("Automation deleted.")
$goto("../automate") $goto("../automate")
} }
</script> </script>

View File

@ -1,7 +1,7 @@
<script> <script>
import { automationStore } from "builderStore" import { automationStore } from "builderStore"
import { database } from "stores/backend" import { database } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import AutomationBlockSetup from "./AutomationBlockSetup.svelte" import AutomationBlockSetup from "./AutomationBlockSetup.svelte"
import { Button, Modal } from "@budibase/bbui" import { Button, Modal } from "@budibase/bbui"
import CreateWebookModal from "../Shared/CreateWebhookModal.svelte" import CreateWebookModal from "../Shared/CreateWebhookModal.svelte"
@ -19,9 +19,9 @@
automation.live = live automation.live = live
automationStore.actions.save({ instanceId, automation }) automationStore.actions.save({ instanceId, automation })
if (live) { if (live) {
notifier.info(`Automation ${automation.name} enabled.`) notifications.info(`Automation ${automation.name} enabled.`)
} else { } else {
notifier.danger(`Automation ${automation.name} disabled.`) notifications.error(`Automation ${automation.name} disabled.`)
} }
} }
@ -30,9 +30,9 @@
automation: $automationStore.selectedAutomation.automation, automation: $automationStore.selectedAutomation.automation,
}) })
if (result.status === 200) { if (result.status === 200) {
notifier.success(`Automation ${automation.name} triggered successfully.`) notifications.success(`Automation ${automation.name} triggered successfully.`)
} else { } else {
notifier.danger(`Failed to trigger automation ${automation.name}.`) notifications.error(`Failed to trigger automation ${automation.name}.`)
} }
} }
@ -41,7 +41,7 @@
instanceId, instanceId,
automation, automation,
}) })
notifier.success(`Automation ${automation.name} saved.`) notifications.success(`Automation ${automation.name} saved.`)
} }
</script> </script>

View File

@ -1,5 +1,5 @@
<script> <script>
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { Input } from "@budibase/bbui" import { Input } from "@budibase/bbui"
import { store, hostingStore } from "builderStore" import { store, hostingStore } from "builderStore"
@ -24,7 +24,7 @@
dummy.select() dummy.select()
document.execCommand("copy") document.execCommand("copy")
document.body.removeChild(dummy) document.body.removeChild(dummy)
notifier.success(`URL copied to clipboard`) notifications.success(`URL copied to clipboard`)
} }
</script> </script>

View File

@ -4,7 +4,7 @@
import AgGrid from "@budibase/svelte-ag-grid" import AgGrid from "@budibase/svelte-ag-grid"
import api from "builderStore/api" import api from "builderStore/api"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import Spinner from "components/common/Spinner.svelte" import Spinner from "components/common/Spinner.svelte"
import DeleteRowsButton from "./buttons/DeleteRowsButton.svelte" import DeleteRowsButton from "./buttons/DeleteRowsButton.svelte"
import { import {
@ -142,7 +142,7 @@
type: "delete", type: "delete",
}) })
data = data.filter(row => !selectedRows.includes(row)) data = data.filter(row => !selectedRows.includes(row))
notifier.success(`Successfully deleted ${selectedRows.length} rows`) notifications.success(`Successfully deleted ${selectedRows.length} rows`)
selectedRows = [] selectedRows = []
} }
</script> </script>

View File

@ -17,7 +17,7 @@
RelationshipTypes, RelationshipTypes,
} from "constants/backend" } from "constants/backend"
import { getAutoColumnInformation, buildAutoColumn } from "builderStore/utils" import { getAutoColumnInformation, buildAutoColumn } from "builderStore/utils"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import ValuesList from "components/common/ValuesList.svelte" import ValuesList from "components/common/ValuesList.svelte"
import DatePicker from "components/common/DatePicker.svelte" import DatePicker from "components/common/DatePicker.svelte"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
@ -82,10 +82,10 @@
function deleteColumn() { function deleteColumn() {
if (field.name === $tables.selected.primaryDisplay) { if (field.name === $tables.selected.primaryDisplay) {
notifier.danger("You cannot delete the display column") notifications.error("You cannot delete the display column")
} else { } else {
tables.deleteField(field) tables.deleteField(field)
notifier.success(`Column ${field.name} deleted.`) notifications.success(`Column ${field.name} deleted.`)
onClosed() onClosed()
} }
} }

View File

@ -1,6 +1,6 @@
<script> <script>
import { tables, rows } from "stores/backend" import { tables, rows } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import RowFieldControl from "../RowFieldControl.svelte" import RowFieldControl from "../RowFieldControl.svelte"
import * as api from "../api" import * as api from "../api"
import { ModalContent } from "@budibase/bbui" import { ModalContent } from "@budibase/bbui"
@ -33,7 +33,7 @@
return false return false
} }
notifier.success("Row saved successfully.") notifications.success("Row saved successfully.")
rows.save(rowResponse) rows.save(rowResponse)
} }
</script> </script>

View File

@ -1,7 +1,7 @@
<script> <script>
import { tables, rows } from "stores/backend" import { tables, rows } from "stores/backend"
import { roles } from "stores/backend" import { roles } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import RowFieldControl from "../RowFieldControl.svelte" import RowFieldControl from "../RowFieldControl.svelte"
import * as backendApi from "../api" import * as backendApi from "../api"
import { ModalContent, Select } from "@budibase/bbui" import { ModalContent, Select } from "@budibase/bbui"
@ -66,7 +66,7 @@
return false return false
} }
notifier.success("User saved successfully.") notifications.success("User saved successfully.")
rows.save(rowResponse) rows.save(rowResponse)
} }
</script> </script>

View File

@ -1,7 +1,7 @@
<script> <script>
import { rows } from "stores/backend" import { rows } from "stores/backend"
import * as api from "../api" import * as api from "../api"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
export let row export let row
@ -14,7 +14,7 @@
async function deleteRow() { async function deleteRow() {
await api.deleteRow(row) await api.deleteRow(row)
notifier.success("Row deleted") notifications.success("Row deleted")
rows.delete(row) rows.delete(row)
} }
</script> </script>

View File

@ -2,7 +2,7 @@
import { ModalContent, Select, Input, Button } from "@budibase/bbui" import { ModalContent, Select, Input, Button } from "@budibase/bbui"
import { onMount } from "svelte" import { onMount } from "svelte"
import api from "builderStore/api" import api from "builderStore/api"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import ErrorsBox from "components/common/ErrorsBox.svelte" import ErrorsBox from "components/common/ErrorsBox.svelte"
import { roles } from "stores/backend" import { roles } from "stores/backend"
@ -61,9 +61,9 @@
// Save/create the role // Save/create the role
const response = await roles.save(selectedRole) const response = await roles.save(selectedRole)
if (response.status === 200) { if (response.status === 200) {
notifier.success("Role saved successfully.") notifications.success("Role saved successfully.")
} else { } else {
notifier.danger("Error saving role.") notifications.error("Error saving role.")
return false return false
} }
} }
@ -73,9 +73,9 @@
const response = await roles.delete(selectedRole) const response = await roles.delete(selectedRole)
if (response.status === 200) { if (response.status === 200) {
changeRole() changeRole()
notifier.success("Role deleted successfully.") notifications.success("Role deleted successfully.")
} else { } else {
notifier.danger("Error deleting role.") notifications.error("Error deleting role.")
} }
} }

View File

@ -2,7 +2,7 @@
import { Button, Select } from "@budibase/bbui" import { Button, Select } from "@budibase/bbui"
import { tables, views } from "stores/backend" import { tables, views } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import analytics from "analytics" import analytics from "analytics"
const CALCULATIONS = [ const CALCULATIONS = [
@ -36,7 +36,7 @@
function saveView() { function saveView() {
views.save(view) views.save(view)
notifier.success(`View ${view.name} saved.`) notifications.success(`View ${view.name} saved.`)
onClosed() onClosed()
analytics.captureEvent("Added View Calculate", { field: view.field }) analytics.captureEvent("Added View Calculate", { field: view.field })
} }

View File

@ -3,7 +3,7 @@
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { views as viewsStore } from "stores/backend" import { views as viewsStore } from "stores/backend"
import { tables } from "stores/backend" import { tables } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import analytics from "analytics" import analytics from "analytics"
export let onClosed export let onClosed
@ -15,7 +15,7 @@
function saveView() { function saveView() {
if (views.includes(name)) { if (views.includes(name)) {
notifier.danger(`View exists with name ${name}.`) notifications.error(`View exists with name ${name}.`)
return return
} }
viewsStore.save({ viewsStore.save({
@ -23,7 +23,7 @@
tableId: $tables.selected._id, tableId: $tables.selected._id,
field, field,
}) })
notifier.success(`View ${name} created`) notifications.success(`View ${name} created`)
onClosed() onClosed()
analytics.captureEvent("View Created", { name }) analytics.captureEvent("View Created", { name })
$goto(`../../view/${name}`) $goto(`../../view/${name}`)

View File

@ -1,7 +1,7 @@
<script> <script>
import { Button, Input, Select, DatePicker } from "@budibase/bbui" import { Button, Input, Select, DatePicker } from "@budibase/bbui"
import { tables, views } from "stores/backend" import { tables, views } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import analytics from "analytics" import analytics from "analytics"
const CONDITIONS = [ const CONDITIONS = [
@ -54,7 +54,7 @@
function saveView() { function saveView() {
views.save(view) views.save(view)
notifier.success(`View ${view.name} saved.`) notifications.success(`View ${view.name} saved.`)
onClosed() onClosed()
analytics.captureEvent("Added View Filter", { analytics.captureEvent("Added View Filter", {
filters: JSON.stringify(view.filters), filters: JSON.stringify(view.filters),

View File

@ -1,7 +1,7 @@
<script> <script>
import { Button, Select } from "@budibase/bbui" import { Button, Select } from "@budibase/bbui"
import { tables, views } from "stores/backend" import { tables, views } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { FIELDS } from "constants/backend" import { FIELDS } from "constants/backend"
export let view = {} export let view = {}
@ -16,7 +16,7 @@
function saveView() { function saveView() {
views.save(view) views.save(view)
notifier.success(`View ${view.name} saved.`) notifications.success(`View ${view.name} saved.`)
onClosed() onClosed()
} }
</script> </script>

View File

@ -1,6 +1,6 @@
<script> <script>
import { roles, permissions as permissionsStore } from "stores/backend" import { roles, permissions as permissionsStore } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { Button, Label, Input, Select, Spacer } from "@budibase/bbui" import { Button, Label, Input, Select, Spacer } from "@budibase/bbui"
export let resourceId export let resourceId
@ -16,7 +16,7 @@
// Show updated permissions in UI: REMOVE // Show updated permissions in UI: REMOVE
permissions = await permissionsStore.forResource(resourceId) permissions = await permissionsStore.forResource(resourceId)
notifier.success("Updated permissions.") notifications.success("Updated permissions.")
// TODO: update permissions // TODO: update permissions
// permissions[] // permissions[]
} }

View File

@ -1,7 +1,7 @@
<script> <script>
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { datasources } from "stores/backend" import { datasources } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { Input, Label, ModalContent } from "@budibase/bbui" import { Input, Label, ModalContent } from "@budibase/bbui"
import TableIntegrationMenu from "../TableIntegrationMenu/index.svelte" import TableIntegrationMenu from "../TableIntegrationMenu/index.svelte"
import analytics from "analytics" import analytics from "analytics"
@ -31,7 +31,7 @@
source: type, source: type,
config, config,
}) })
notifier.success(`Datasource ${name} created successfully.`) notifications.success(`Datasource ${name} created successfully.`)
analytics.captureEvent("Datasource Created", { name }) analytics.captureEvent("Datasource Created", { name })
// Navigate to new datasource // Navigate to new datasource

View File

@ -1,7 +1,7 @@
<script> <script>
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { datasources } from "stores/backend" import { datasources } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { DropdownMenu } from "@budibase/bbui" import { DropdownMenu } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns" import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
@ -26,7 +26,7 @@
console.log(wasSelectedSource) console.log(wasSelectedSource)
console.log(datasource) console.log(datasource)
await datasources.delete(datasource) await datasources.delete(datasource)
notifier.success("Datasource deleted") notifications.success("Datasource deleted")
// navigate to first index page if the source you are deleting is selected // navigate to first index page if the source you are deleting is selected
if (wasSelectedSource === datasource._id) { if (wasSelectedSource === datasource._id) {
$goto("./datasource") $goto("./datasource")

View File

@ -1,5 +1,5 @@
<script> <script>
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { DropdownMenu } from "@budibase/bbui" import { DropdownMenu } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns" import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
@ -21,7 +21,7 @@
async function deleteQuery() { async function deleteQuery() {
await queries.delete(query) await queries.delete(query)
notifier.success("Query deleted") notifications.success("Query deleted")
hideEditor() hideEditor()
} }
</script> </script>

View File

@ -1,6 +1,6 @@
<script> <script>
import { Select, Label } from "@budibase/bbui" import { Select, Label } from "@budibase/bbui"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { FIELDS } from "constants/backend" import { FIELDS } from "constants/backend"
import api from "builderStore/api" import api from "builderStore/api"
@ -60,7 +60,7 @@
} }
if (response.status !== 200) { if (response.status !== 200) {
notifier.danger("CSV Invalid, please try another CSV file") notifications.error("CSV Invalid, please try another CSV file")
return [] return []
} }
} }
@ -68,7 +68,7 @@
async function handleFile(evt) { async function handleFile(evt) {
const fileArray = Array.from(evt.target.files) const fileArray = Array.from(evt.target.files)
if (fileArray.some(file => file.size >= FILE_SIZE_LIMIT)) { if (fileArray.some(file => file.size >= FILE_SIZE_LIMIT)) {
notifier.danger( notifications.error(
`Files cannot exceed ${FILE_SIZE_LIMIT / `Files cannot exceed ${FILE_SIZE_LIMIT /
BYTES_IN_MB}MB. Please try again with smaller files.` BYTES_IN_MB}MB. Please try again with smaller files.`
) )

View File

@ -2,7 +2,7 @@
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { store } from "builderStore" import { store } from "builderStore"
import { tables } from "stores/backend" import { tables } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { Input, Label, ModalContent, Toggle } from "@budibase/bbui" import { Input, Label, ModalContent, Toggle } from "@budibase/bbui"
import TableDataImport from "../TableDataImport.svelte" import TableDataImport from "../TableDataImport.svelte"
import analytics from "analytics" import analytics from "analytics"
@ -60,7 +60,7 @@
// Create table // Create table
const table = await tables.save(newTable) const table = await tables.save(newTable)
notifier.success(`Table ${name} created successfully.`) notifications.success(`Table ${name} created successfully.`)
analytics.captureEvent("Table Created", { name }) analytics.captureEvent("Table Created", { name })
// Create auto screens // Create auto screens

View File

@ -2,7 +2,7 @@
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { store, allScreens } from "builderStore" import { store, allScreens } from "builderStore"
import { tables } from "stores/backend" import { tables } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { DropdownMenu, Button, Input } from "@budibase/bbui" import { DropdownMenu, Button, Input } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns" import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
@ -42,7 +42,7 @@
await tables.delete(table) await tables.delete(table)
store.actions.screens.delete(templateScreens) store.actions.screens.delete(templateScreens)
await tables.fetch() await tables.fetch()
notifier.success("Table deleted") notifications.success("Table deleted")
if (wasSelectedTable._id === table._id) { if (wasSelectedTable._id === table._id) {
$goto("./table") $goto("./table")
} }
@ -51,7 +51,7 @@
async function save() { async function save() {
await tables.save(table) await tables.save(table)
notifier.success("Table renamed successfully") notifications.success("Table renamed successfully")
hideEditor() hideEditor()
} }

View File

@ -1,7 +1,7 @@
<script> <script>
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { views } from "stores/backend" import { views } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { DropdownMenu, Button, Input } from "@budibase/bbui" import { DropdownMenu, Button, Input } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns" import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
@ -33,7 +33,7 @@
originalName, originalName,
...view, ...view,
}) })
notifier.success("View renamed successfully") notifications.success("View renamed successfully")
hideEditor() hideEditor()
} }
@ -41,7 +41,7 @@
const name = view.name const name = view.name
const id = view.tableId const id = view.tableId
await views.delete(name) await views.delete(name)
notifier.success("View deleted") notifications.success("View deleted")
$goto(`./table/${id}`) $goto(`./table/${id}`)
} }
</script> </script>

View File

@ -1,5 +1,5 @@
<script> <script>
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { Dropzone } from "@budibase/bbui" import { Dropzone } from "@budibase/bbui"
import api from "builderStore/api" import api from "builderStore/api"
@ -8,7 +8,7 @@
const BYTES_IN_MB = 1000000 const BYTES_IN_MB = 1000000
function handleFileTooLarge(fileSizeLimit) { function handleFileTooLarge(fileSizeLimit) {
notifier.danger( notifications.error(
`Files cannot exceed ${fileSizeLimit / `Files cannot exceed ${fileSizeLimit /
BYTES_IN_MB}MB. Please try again with smaller files.` BYTES_IN_MB}MB. Please try again with smaller files.`
) )

View File

@ -1,70 +0,0 @@
<script>
import { notificationStore } from "builderStore/store/notifications"
import { flip } from "svelte/animate"
import { fly } from "svelte/transition"
export let themes = {
danger: "#E26D69",
success: "#84C991",
warning: "#f0ad4e",
info: "#5bc0de",
default: "#aaaaaa",
}
export let timeout = 3000
$: if ($notificationStore.notifications.length) {
setTimeout(() => {
notificationStore.update(state => {
state.notifications.shift()
state.notifications = state.notifications
return state
})
}, timeout)
}
</script>
<div class="notifications">
{#each $notificationStore.notifications as notification (notification.id)}
<div
animate:flip
class="toast"
style="background: {themes[notification.type]};"
transition:fly={{ y: -30 }}>
<div class="content">{notification.message}</div>
{#if notification.icon}<i class={notification.icon} />{/if}
</div>
{/each}
</div>
<style>
.notifications {
position: fixed;
top: 10px;
left: 0;
right: 0;
margin: 0 auto;
padding: 0;
z-index: 9999;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
pointer-events: none;
}
.toast {
flex: 0 0 auto;
margin-bottom: 10px;
border-radius: var(--border-radius-s);
/* The toasts now support being auto sized, so this static width could be removed */
width: 40vw;
}
.content {
padding: 10px;
display: block;
color: white;
font-weight: 500;
}
</style>

View File

@ -4,7 +4,7 @@
import { slide } from "svelte/transition" import { slide } from "svelte/transition"
import { Heading, Body, Button, Modal, ModalContent } from "@budibase/bbui" import { Heading, Body, Button, Modal, ModalContent } from "@budibase/bbui"
import api from "builderStore/api" import api from "builderStore/api"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import CreateWebhookDeploymentModal from "./CreateWebhookDeploymentModal.svelte" import CreateWebhookDeploymentModal from "./CreateWebhookDeploymentModal.svelte"
import { store, hostingStore } from "builderStore" import { store, hostingStore } from "builderStore"
@ -75,7 +75,7 @@
} catch (err) { } catch (err) {
console.error(err) console.error(err)
clearInterval(poll) clearInterval(poll)
notifier.danger("Error fetching deployment history. Please try again.") notifications.error("Error fetching deployment history. Please try again.")
} }
} }

View File

@ -1,7 +1,7 @@
<script> <script>
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { store } from "builderStore" import { store } from "builderStore"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { DropdownMenu, Modal, ModalContent, Input } from "@budibase/bbui" import { DropdownMenu, Modal, ModalContent, Input } from "@budibase/bbui"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns" import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
@ -18,9 +18,9 @@
const deleteLayout = async () => { const deleteLayout = async () => {
try { try {
await store.actions.layouts.delete(layout) await store.actions.layouts.delete(layout)
notifier.success(`Layout ${layout.name} deleted successfully.`) notifications.success(`Layout ${layout.name} deleted successfully.`)
} catch (err) { } catch (err) {
notifier.danger(`Error deleting layout: ${err.message}`) notifications.error(`Error deleting layout: ${err.message}`)
} }
} }
@ -29,9 +29,9 @@
const layoutToSave = cloneDeep(layout) const layoutToSave = cloneDeep(layout)
layoutToSave.name = name layoutToSave.name = name
await store.actions.layouts.save(layoutToSave) await store.actions.layouts.save(layoutToSave)
notifier.success(`Layout saved successfully.`) notifications.success(`Layout saved successfully.`)
} catch (err) { } catch (err) {
notifier.danger(`Error saving layout: ${err.message}`) notifications.error(`Error saving layout: ${err.message}`)
} }
} }
</script> </script>

View File

@ -1,7 +1,7 @@
<script> <script>
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { store, allScreens } from "builderStore" import { store, allScreens } from "builderStore"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { DropdownMenu, Modal, ModalContent } from "@budibase/bbui" import { DropdownMenu, Modal, ModalContent } from "@budibase/bbui"
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns" import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
@ -20,9 +20,9 @@
store.actions.routing.fetch() store.actions.routing.fetch()
confirmDeleteDialog.hide() confirmDeleteDialog.hide()
$goto("../") $goto("../")
notifier.success("Deleted screen successfully.") notifications.success("Deleted screen successfully.")
} catch (err) { } catch (err) {
notifier.danger("Error deleting screen") notifications.error("Error deleting screen")
} }
} }
</script> </script>

View File

@ -1,6 +1,6 @@
<script> <script>
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { store } from "builderStore" import { store } from "builderStore"
import { Input, ModalContent } from "@budibase/bbui" import { Input, ModalContent } from "@budibase/bbui"
@ -9,9 +9,9 @@
async function save() { async function save() {
try { try {
await store.actions.layouts.save({ name }) await store.actions.layouts.save({ name })
notifier.success(`Layout ${name} created successfully`) notifications.success(`Layout ${name} created successfully`)
} catch (err) { } catch (err) {
notifier.danger(`Error creating layout ${name}.`) notifications.error(`Error creating layout ${name}.`)
} }
} }
</script> </script>

View File

@ -15,7 +15,7 @@
queries as queriesStore, queries as queriesStore,
} from "stores/backend" } from "stores/backend"
import { datasources, integrations } from "stores/backend" import { datasources, integrations } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import ParameterBuilder from "components/integration/QueryParameterBuilder.svelte" import ParameterBuilder from "components/integration/QueryParameterBuilder.svelte"
import IntegrationQueryEditor from "components/integration/index.svelte" import IntegrationQueryEditor from "components/integration/index.svelte"
@ -108,7 +108,7 @@
blue blue
thin thin
on:click={() => { on:click={() => {
notifier.success('Query parameters saved.') notifications.success('Query parameters saved.')
handleSelected(value) handleSelected(value)
drawer.hide() drawer.hide()
}}> }}>

View File

@ -1,7 +1,7 @@
<script> <script>
import { Button, Drawer } from "@budibase/bbui" import { Button, Drawer } from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import EventEditor from "./EventEditor.svelte" import EventEditor from "./EventEditor.svelte"
import { automationStore } from "builderStore" import { automationStore } from "builderStore"
@ -22,7 +22,7 @@
} }
dispatch("change", value) dispatch("change", value)
notifier.success("Component actions saved.") notifications.success("Component actions saved.")
drawer.hide() drawer.hide()
} }

View File

@ -1,7 +1,7 @@
<script> <script>
import { Button, Drawer, Spacer, Body } from "@budibase/bbui" import { Button, Drawer, Spacer, Body } from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { import {
getDatasourceForProvider, getDatasourceForProvider,
getSchemaForDatasource, getSchemaForDatasource,
@ -26,7 +26,7 @@
const saveFilter = async () => { const saveFilter = async () => {
dispatch("change", tempValue) dispatch("change", tempValue)
notifier.success("Filters saved.") notifications.success("Filters saved.")
drawer.hide() drawer.hide()
} }

View File

@ -10,7 +10,7 @@
Spacer, Spacer,
Switcher, Switcher,
} from "@budibase/bbui" } from "@budibase/bbui"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import api from "builderStore/api" import api from "builderStore/api"
import IntegrationQueryEditor from "components/integration/index.svelte" import IntegrationQueryEditor from "components/integration/index.svelte"
import ExternalDataSourceTable from "components/backend/DataTable/ExternalDataSourceTable.svelte" import ExternalDataSourceTable from "components/backend/DataTable/ExternalDataSourceTable.svelte"
@ -89,13 +89,13 @@
data = json.rows || [] data = json.rows || []
if (data.length === 0) { if (data.length === 0) {
notifier.info( notifications.info(
"Query results empty. Please execute a query with results to create your schema." "Query results empty. Please execute a query with results to create your schema."
) )
return return
} }
notifier.success("Query executed successfully.") notifications.success("Query executed successfully.")
// Assume all the fields are strings and create a basic schema from the // Assume all the fields are strings and create a basic schema from the
// unique fields returned by the server // unique fields returned by the server
@ -104,7 +104,7 @@
type: "STRING", type: "STRING",
})) }))
} catch (err) { } catch (err) {
notifier.danger(`Query Error: ${err.message}`) notifications.error(`Query Error: ${err.message}`)
console.error(err) console.error(err)
} }
} }
@ -112,11 +112,11 @@
async function saveQuery() { async function saveQuery() {
try { try {
const { _id } = await queries.save(query.datasourceId, query) const { _id } = await queries.save(query.datasourceId, query)
notifier.success(`Query saved successfully.`) notifications.success(`Query saved successfully.`)
$goto(`../../${_id}`) $goto(`../../${_id}`)
} catch (err) { } catch (err) {
console.error(err) console.error(err)
notifier.danger(`Error creating query. ${err.message}`) notifications.error(`Error creating query. ${err.message}`)
} }
} }
</script> </script>

View File

@ -1,7 +1,7 @@
<script> <script>
import { Input, Label, TextButton } from "@budibase/bbui" import { Input, Label, TextButton } from "@budibase/bbui"
import api from "builderStore/api" import api from "builderStore/api"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { database } from "stores/backend" import { database } from "stores/backend"
import analytics from "analytics" import analytics from "analytics"
@ -11,7 +11,7 @@
if (key === "budibase") { if (key === "budibase") {
const isValid = await analytics.identifyByApiKey(value) const isValid = await analytics.identifyByApiKey(value)
if (!isValid) { if (!isValid) {
notifier.danger("Your API Key is invalid.") notifications.error("Your API Key is invalid.")
keys = { ...keys } keys = { ...keys }
return return
} }
@ -19,7 +19,7 @@
const response = await api.put(`/api/keys/${key}`, { value }) const response = await api.put(`/api/keys/${key}`, { value })
const res = await response.json() const res = await response.json()
keys = { ...keys, ...res } keys = { ...keys, ...res }
notifier.success("API Key saved.") notifications.success("API Key saved.")
} }
// Get Keys // Get Keys

View File

@ -3,7 +3,7 @@
import { Heading } from "@budibase/bbui" import { Heading } from "@budibase/bbui"
import { Spacer } from "@budibase/bbui" import { Spacer } from "@budibase/bbui"
import api from "builderStore/api" import api from "builderStore/api"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import Spinner from "components/common/Spinner.svelte" import Spinner from "components/common/Spinner.svelte"
import download from "downloadjs" import download from "downloadjs"
@ -17,10 +17,10 @@
download( download(
`/api/backups/export?appId=${_id}&appname=${encodeURIComponent(name)}` `/api/backups/export?appId=${_id}&appname=${encodeURIComponent(name)}`
) )
notifier.success("App Export Complete.") notifications.success("App Export Complete.")
} catch (err) { } catch (err) {
console.error(err) console.error(err)
notifier.danger("App Export Failed.") notifications.error("App Export Failed.")
} finally { } finally {
appExportLoading = false appExportLoading = false
} }

View File

@ -1,5 +1,5 @@
<script> <script>
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { hostingStore } from "builderStore" import { hostingStore } from "builderStore"
import { HostingTypes } from "constants/backend" import { HostingTypes } from "constants/backend"
import { Input, ModalContent, Toggle } from "@budibase/bbui" import { Input, ModalContent, Toggle } from "@budibase/bbui"
@ -23,9 +23,9 @@
} }
try { try {
await hostingStore.actions.save(hostingInfo) await hostingStore.actions.save(hostingInfo)
notifier.success(`Settings saved.`) notifications.success(`Settings saved.`)
} catch (err) { } catch (err) {
notifier.danger(`Failed to update builder settings.`) notifications.error(`Failed to update builder settings.`)
} }
} }

View File

@ -1,6 +1,6 @@
<script> <script>
import { writable, get as svelteGet } from "svelte/store" import { writable, get as svelteGet } from "svelte/store"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import { store, automationStore, hostingStore } from "builderStore" import { store, automationStore, hostingStore } from "builderStore"
import { string, object } from "yup" import { string, object } from "yup"
import api, { get } from "builderStore/api" import api, { get } from "builderStore/api"
@ -162,7 +162,7 @@
$goto(`./${appJson._id}`) $goto(`./${appJson._id}`)
} catch (error) { } catch (error) {
console.error(error) console.error(error)
notifier.danger(error) notifications.error(error)
submitting = false submitting = false
} }
} }

View File

@ -13,7 +13,7 @@
function handleFile(evt) { function handleFile(evt) {
const fileArray = Array.from(evt.target.files) const fileArray = Array.from(evt.target.files)
if (fileArray.some(file => file.size >= FILE_SIZE_LIMIT)) { if (fileArray.some(file => file.size >= FILE_SIZE_LIMIT)) {
notifier.danger( notifications.error(
`Files cannot exceed ${FILE_SIZE_LIMIT / `Files cannot exceed ${FILE_SIZE_LIMIT /
BYTES_IN_MB}MB. Please try again with smaller files.` BYTES_IN_MB}MB. Please try again with smaller files.`
) )

View File

@ -9,7 +9,7 @@
const json = await response.json() const json = await response.json()
config = json.query config = json.query
} catch (err) { } catch (err) {
notifier.danger("Error fetching datasource configuration options.") notifications.error("Error fetching datasource configuration options.")
console.error(err) console.error(err)
} }
} }

View File

@ -2,7 +2,7 @@
import { goto, beforeUrlChange } from "@roxi/routify" import { goto, beforeUrlChange } from "@roxi/routify"
import { Button, Heading, Body, Spacer } from "@budibase/bbui" import { Button, Heading, Body, Spacer } from "@budibase/bbui"
import { datasources, integrations, queries } from "stores/backend" import { datasources, integrations, queries } from "stores/backend"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import IntegrationConfigForm from "components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte" import IntegrationConfigForm from "components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte"
import ICONS from "components/backend/DatasourceNavigator/icons" import ICONS from "components/backend/DatasourceNavigator/icons"
@ -14,7 +14,7 @@
async function saveDatasource() { async function saveDatasource() {
// Create datasource // Create datasource
await datasources.save(datasource) await datasources.save(datasource)
notifier.success(`Datasource ${name} saved successfully.`) notifications.success(`Datasource ${name} saved successfully.`)
unsaved = false unsaved = false
} }
@ -32,7 +32,7 @@
$beforeUrlChange((event, store) => { $beforeUrlChange((event, store) => {
if (unsaved) { if (unsaved) {
notifier.danger( notifications.error(
"Unsaved changes. Please save your datasource configuration before leaving." "Unsaved changes. Please save your datasource configuration before leaving."
) )
return false return false

View File

@ -1,7 +1,7 @@
<script> <script>
import { Button, Modal } from "@budibase/bbui" import { Button, Modal } from "@budibase/bbui"
import { store, hostingStore } from "builderStore" import { store, hostingStore } from "builderStore"
import { notifier } from "builderStore/store/notifications" import { notifications } from "@budibase/bbui"
import api from "builderStore/api" import api from "builderStore/api"
import DeploymentHistory from "components/deploy/DeploymentHistory.svelte" import DeploymentHistory from "components/deploy/DeploymentHistory.svelte"
import analytics from "analytics" import analytics from "analytics"
@ -21,7 +21,7 @@
const response = await api.get(`/api/keys/`) const response = await api.get(`/api/keys/`)
const userKeys = await response.json() const userKeys = await response.json()
if (!userKeys.budibase) { if (!userKeys.budibase) {
notifier.danger( notifications.error(
"No budibase API Keys configured. You must set either a self hosted or cloud API key to deploy your budibase app." "No budibase API Keys configured. You must set either a self hosted or cloud API key to deploy your budibase app."
) )
return return
@ -31,7 +31,7 @@
const DEPLOY_URL = `/api/deploy` const DEPLOY_URL = `/api/deploy`
try { try {
notifier.info(`Deployment started. Please wait.`) notifications.info(`Deployment started. Please wait.`)
const response = await api.post(DEPLOY_URL) const response = await api.post(DEPLOY_URL)
const json = await response.json() const json = await response.json()
if (response.status !== 200) { if (response.status !== 200) {
@ -52,7 +52,7 @@
hostingType: $hostingStore.hostingInfo?.type, hostingType: $hostingStore.hostingInfo?.type,
}) })
analytics.captureException(err) analytics.captureException(err)
notifier.danger("Deployment unsuccessful. Please try again later.") notifications.error("Deployment unsuccessful. Please try again later.")
} }
} }
</script> </script>

View File

@ -824,6 +824,11 @@
estree-walker "^1.0.1" estree-walker "^1.0.1"
micromatch "^4.0.2" micromatch "^4.0.2"
"@spectrum-css/toast@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@spectrum-css/toast/-/toast-3.0.1.tgz#36f62ea05302761e59b9d53e05f6c04423861796"
integrity sha512-jov++S358BrN2tmMfaoYk1N6u9HojgeuQk61keXrK2m3VE5/n94x7Lg3kIPeSWO0odyDfBlMqT9jacbRey3QTg==
"@types/estree@0.0.39": "@types/estree@0.0.39":
version "0.0.39" version "0.0.39"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"