Skip to content

Commit

Permalink
Merge pull request #14219 from Budibase/feat/row-actions
Browse files Browse the repository at this point in the history
Row actions automation creation
  • Loading branch information
adrinr authored Jul 25, 2024
2 parents aedf3e3 + 22f86be commit afd9ad9
Show file tree
Hide file tree
Showing 28 changed files with 583 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
automationStore,
selectedAutomation,
permissions,
selectedAutomationDisplayData,
} from "stores/builder"
import {
Icon,
Expand All @@ -14,6 +15,7 @@
notifications,
Label,
AbsTooltip,
InlineAlert,
} from "@budibase/bbui"
import AutomationBlockSetup from "../../SetupPanel/AutomationBlockSetup.svelte"
import CreateWebhookModal from "components/automation/Shared/CreateWebhookModal.svelte"
Expand Down Expand Up @@ -49,6 +51,8 @@
$: isAppAction && setPermissions(role)
$: isAppAction && getPermissions(automationId)
$: triggerInfo = $selectedAutomationDisplayData?.triggerInfo
async function setPermissions(role) {
if (!role || !automationId) {
return
Expand Down Expand Up @@ -183,6 +187,12 @@
{block}
{webhookModal}
/>
{#if isTrigger && triggerInfo}
<InlineAlert
header={triggerInfo.type}
message={`This trigger is tied to the row action ${triggerInfo.rowAction.name} on your ${triggerInfo.table.name} table`}
/>
{/if}
{#if lastStep}
<Button on:click={() => testDataModal.show()} cta>
Finish and test automation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
// Check the schema to see if required fields have been entered
$: isError =
!isTriggerValid(trigger) ||
!trigger.schema.outputs.required?.every(
!(trigger.schema.outputs.required || []).every(
required => $memoTestData?.[required] || required !== "row"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
contextMenuStore,
} from "stores/builder"
import { notifications, Icon } from "@budibase/bbui"
import { sdk } from "@budibase/shared-core"
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import UpdateAutomationModal from "components/automation/AutomationPanel/UpdateAutomationModal.svelte"
import NavItem from "components/common/NavItem.svelte"
Expand Down Expand Up @@ -35,45 +36,53 @@
}
const getContextMenuItems = () => {
return [
{
icon: "Delete",
name: "Delete",
keyBind: null,
visible: true,
disabled: false,
callback: confirmDeleteDialog.show,
},
{
icon: "Edit",
name: "Edit",
keyBind: null,
visible: true,
disabled: false,
callback: updateAutomationDialog.show,
},
{
icon: "Duplicate",
name: "Duplicate",
keyBind: null,
visible: true,
disabled: automation.definition.trigger.name === "Webhook",
callback: duplicateAutomation,
},
{
icon: automation.disabled ? "CheckmarkCircle" : "Cancel",
name: automation.disabled ? "Activate" : "Pause",
keyBind: null,
visible: true,
disabled: false,
callback: () => {
automationStore.actions.toggleDisabled(
automation._id,
automation.disabled
)
},
const isRowAction = sdk.automations.isRowAction(automation)
const result = []
if (!isRowAction) {
result.push(
...[
{
icon: "Delete",
name: "Delete",
keyBind: null,
visible: true,
disabled: false,
callback: confirmDeleteDialog.show,
},
{
icon: "Edit",
name: "Edit",
keyBind: null,
visible: true,
disabled: false,
callback: updateAutomationDialog.show,
},
{
icon: "Duplicate",
name: "Duplicate",
keyBind: null,
visible: true,
disabled: automation.definition.trigger.name === "Webhook",
callback: duplicateAutomation,
},
]
)
}
result.push({
icon: automation.disabled ? "CheckmarkCircle" : "Cancel",
name: automation.disabled ? "Activate" : "Pause",
keyBind: null,
visible: true,
disabled: false,
callback: () => {
automationStore.actions.toggleDisabled(
automation._id,
automation.disabled
)
},
]
})
return result
}
const openContextMenu = e => {
Expand All @@ -89,7 +98,7 @@
on:contextmenu={openContextMenu}
{icon}
iconColor={"var(--spectrum-global-color-gray-900)"}
text={automation.name}
text={automation.displayName}
selected={automation._id === $selectedAutomation?._id}
hovering={automation._id === $contextMenuStore.id}
on:click={() => automationStore.actions.select(automation._id)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@
automation.name.toLowerCase().includes(searchString.toLowerCase())
)
})
.map(automation => ({
...automation,
displayName:
$automationStore.automationDisplayData[automation._id].displayName ||
automation.name,
}))
.sort((a, b) => {
const lowerA = a.name.toLowerCase()
const lowerB = b.name.toLowerCase()
const lowerA = a.displayName.toLowerCase()
const lowerB = b.displayName.toLowerCase()
return lowerA > lowerB ? 1 : -1
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,7 @@
options={value.enum}
getOptionLabel={(x, idx) =>
value.pretty ? value.pretty[idx] : x}
disabled={value.readonly}
/>
{:else if value.type === "json"}
<Editor
Expand All @@ -884,13 +885,15 @@
mode="json"
value={inputData[key]?.value}
on:change={e => onChange({ [key]: e.detail })}
readOnly={value.readonly}
/>
{:else if value.type === "boolean"}
<div style="margin-top: 10px">
<Checkbox
text={value.title}
value={inputData[key]}
on:change={e => onChange({ [key]: e.detail })}
disabled={value.readonly}
/>
</div>
{:else if value.type === "date"}
Expand All @@ -904,6 +907,7 @@
allowJS={true}
updateOnChange={false}
drawerLeft="260px"
disabled={value.readonly}
>
<DatePicker
value={inputData[key]}
Expand All @@ -915,6 +919,7 @@
on:change={e => onChange({ [key]: e.detail })}
value={inputData[key]}
options={Object.keys(table?.schema || {})}
disabled={value.readonly}
/>
{:else if value.type === "attachment" || value.type === "signature_single"}
<div class="attachment-field-wrapper">
Expand Down Expand Up @@ -1028,6 +1033,7 @@
{isTrigger}
value={inputData[key]}
on:change={e => onChange({ [key]: e.detail })}
disabled={value.readonly}
/>
{:else if value.customType === "webhookUrl"}
<WebhookDisplay value={inputData[key]} />
Expand Down
41 changes: 22 additions & 19 deletions packages/builder/src/stores/builder/automations.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const initialAutomationState = {
ACTION: [],
},
selectedAutomationId: null,
automationDisplayData: {},
}

// If this functions, remove the actions elements
Expand Down Expand Up @@ -58,18 +59,19 @@ const automationActions = store => ({
return response
},
fetch: async () => {
const responses = await Promise.all([
API.getAutomations(),
const [automationResponse, definitions] = await Promise.all([
API.getAutomations({ enrich: true }),
API.getAutomationDefinitions(),
])
store.update(state => {
state.automations = responses[0]
state.automations = automationResponse.automations
state.automations.sort((a, b) => {
return a.name < b.name ? -1 : 1
})
state.automationDisplayData = automationResponse.builderData
state.blockDefinitions = {
TRIGGER: responses[1].trigger,
ACTION: responses[1].action,
TRIGGER: definitions.trigger,
ACTION: definitions.action,
}
return state
})
Expand Down Expand Up @@ -102,19 +104,8 @@ const automationActions = store => ({
},
save: async automation => {
const response = await API.updateAutomation(automation)
store.update(state => {
const updatedAutomation = response.automation
const existingIdx = state.automations.findIndex(
existing => existing._id === automation._id
)
if (existingIdx !== -1) {
state.automations.splice(existingIdx, 1, updatedAutomation)
return state
} else {
state.automations = [...state.automations, updatedAutomation]
}
return state
})

await store.actions.fetch()
return response.automation
},
delete: async automation => {
Expand Down Expand Up @@ -308,7 +299,9 @@ const automationActions = store => ({
if (!automation) {
return
}
delete newAutomation.definition.stepNames[blockId]
if (newAutomation.definition.stepNames) {
delete newAutomation.definition.stepNames[blockId]
}

await store.actions.save(newAutomation)
},
Expand Down Expand Up @@ -384,3 +377,13 @@ export const selectedAutomation = derived(automationStore, $automationStore => {
x => x._id === $automationStore.selectedAutomationId
)
})

export const selectedAutomationDisplayData = derived(
[automationStore, selectedAutomation],
([$automationStore, $selectedAutomation]) => {
if (!$selectedAutomation._id) {
return null
}
return $automationStore.automationDisplayData[$selectedAutomation._id]
}
)
2 changes: 2 additions & 0 deletions packages/builder/src/stores/builder/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
automationStore,
selectedAutomation,
automationHistoryStore,
selectedAutomationDisplayData,
} from "./automations.js"
import { userStore, userSelectedResourceMap, isOnlyUser } from "./users.js"
import { deploymentStore } from "./deployments.js"
Expand Down Expand Up @@ -44,6 +45,7 @@ export {
previewStore,
automationStore,
selectedAutomation,
selectedAutomationDisplayData,
automationHistoryStore,
sortedScreens,
userStore,
Expand Down
9 changes: 7 additions & 2 deletions packages/frontend-core/src/api/automations.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,14 @@ export const buildAutomationEndpoints = API => ({
/**
* Gets a list of all automations.
*/
getAutomations: async () => {
getAutomations: async ({ enrich }) => {
const params = new URLSearchParams()
if (enrich) {
params.set("enrich", true)
}

return await API.get({
url: "/api/automations",
url: `/api/automations?${params.toString()}`,
})
},

Expand Down
20 changes: 18 additions & 2 deletions packages/server/src/api/controllers/automation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as triggers from "../../automations/triggers"
import { sdk as coreSdk } from "@budibase/shared-core"
import { DocumentType } from "../../db/utils"
import { updateTestHistory, removeDeprecated } from "../../automations/utils"
import { setTestFlag, clearTestFlag } from "../../utilities/redis"
Expand All @@ -11,6 +12,7 @@ import {
AutomationResults,
UserCtx,
DeleteAutomationResponse,
FetchAutomationResponse,
} from "@budibase/types"
import { getActionDefinitions as actionDefs } from "../../automations/actions"
import sdk from "../../sdk"
Expand Down Expand Up @@ -73,8 +75,17 @@ export async function update(ctx: UserCtx) {
builderSocket?.emitAutomationUpdate(ctx, automation)
}

export async function fetch(ctx: UserCtx) {
ctx.body = await sdk.automations.fetch()
export async function fetch(ctx: UserCtx<void, FetchAutomationResponse>) {
const query: { enrich?: string } = ctx.request.query || {}
const enrich = query.enrich === "true"

const automations = await sdk.automations.fetch()
ctx.body = { automations }
if (enrich) {
ctx.body.builderData = await sdk.automations.utils.getBuilderData(
automations
)
}
}

export async function find(ctx: UserCtx) {
Expand All @@ -84,6 +95,11 @@ export async function find(ctx: UserCtx) {
export async function destroy(ctx: UserCtx<void, DeleteAutomationResponse>) {
const automationId = ctx.params.id

const automation = await sdk.automations.get(ctx.params.id)
if (coreSdk.automations.isRowAction(automation)) {
ctx.throw("Row actions automations cannot be deleted", 422)
}

ctx.body = await sdk.automations.remove(automationId, ctx.params.rev)
builderSocket?.emitAutomationDeletion(ctx, automationId)
}
Expand Down
Loading

0 comments on commit afd9ad9

Please sign in to comment.