This guide walks you through building a UI module that deletes submission records in bulk. The module handles the two-stage delete process: archiving records first (soft delete), then permanently removing them if needed (hard delete). Creators set the date range in the UI, and the module displays job status after each stage.
Download the example module bundle to use as a starting point. After importing, replace every placeholder before using the module:
Placeholder | Appears in | Replace with. |
|---|---|---|
|
| The resource ID of the Data Model or module containing the records to delete. |
BDO Delete is disabled by default. Contact an Unqork representative to enable it for your environment. Hard delete is permanent and cannot be reversed.
Prerequisites
Creator or Express Administrator access to your workspace.
The BDO Delete endpoint enabled by an Unqork representative.
The resource ID of the Data Model or module containing the records to delete.
Familiarity with the Plug-In, Decisions, and Button components.
Module Overview
Organize the module into three field groups: for initialization logic, for the Creator-facing UI, and for the backend Plug-In component sequence.
Name | Key | Component | Purpose |
|---|---|---|---|
On-Load Initializer |
| Initializer | Triggers on page load. |
Refresh Button |
| Button | Lets the Creator check job status manually; enabled when a job is running. |
Delete Button |
| Button | Starts the soft-delete sequence. |
Hard Delete Button |
| Button | Starts the hard-delete sequence; enabled when soft delete completes. |
Start Date |
| Date | Filters records created after this date. |
End Date |
| Date Input | Filters records created on or before this date. |
Error Initializer |
| Initializer | Sets the response field to indicate failure. |
Soft Delete |
| Plug-In | Calls the Delete endpoint to archive records in the date range. |
Hard Delete |
| Plug-In | Calls the Delete endpoint with |
Get Job Status |
| Plug-In | Checks delete progress using the job ID. |
Check Status Rule |
| Decisions | Shows a status message and enables the |
The example Property IDs in this guide use a
pluginprefix (for example,pluginExport) for clarity. The platform default for Plug-In components isplug— see Property ID Naming Conventions.
How to read settings tables
The tables below describe each configurable option as it shows in the platform. Values are formatted as follows:
inline code— a value to type exactly as shown | Bold — a value selected from a drop-down, radio button, tab, or choice chip | ON/OFF — toggle state | ✓ — checkbox checked | ☐ — checkbox unchecked
Set Up the Field Groups
Create three field groups in the module to keep components organized.
Field Group | Contains |
|---|---|
| The on-load Initializer that fires when the page renders. |
| The buttons, date inputs, and HTML instructions the Creator interacts with. |
| All Plug-In components, status logic, the error Initializer, and hidden fields. |
Create the Supporting Fields
Add the following fields to fgConfig. These fields carry data between components throughout the delete sequence.
Property ID | Component | Default | Purpose |
|---|---|---|---|
| Hidden | — | Stores the delete job ID returned by |
| Hidden | — | Stores the current job status returned by |
| Hidden | — | Set to |
Before You Begin
Unqork recommends exporting a copy of records before running a bulk delete. See Build a Bulk Download Module for those steps.
BDO Delete removes a maximum of 500,000 records per operation. For larger collections, run the operation multiple times.
Configure initOnload
The initOnload Initializer component fires when the module first loads and serves as the module's entry point. It has no outputs and no connections to other components.
Add an Initializer component to
fgOnLoad.Configure the following settings:
Setting
Value
Property ID
initOnloadTrigger Type
New Submission
Configure btnRefresh
The btnRefresh Button component lets the Creator manually re-check job status. It triggers the pluginGetJobDetails Plug-In component on click, and the ruleCheckStatus Decisions component enables it a job is running. It starts disabled.
Add a Button component to
fgUI.Configure the following settings:
Setting
Value
Property ID
btnRefreshLabel
RefreshAction
Event
Initial State
Disabled
Under Triggers, set the On Click drop-down to
pluginGetJobDetails.
Configure btnDelete
The btnDelete Button component starts the soft-delete sequence. After validation passes, it triggers the pluginDelete Plug-In component.
Add a Button component to
fgUIafter the Refresh button.Configure the following settings:
Setting
Value
Property ID
btnDeleteLabel
Delete RecordsAction
Validate
Theme
Danger
Under Triggers, set the On Validation Success drop-down to
pluginDelete.
Configure btnHardDelete
The btnHardDelete Button component permanently removes the archived records. It starts disabled and is enabled by the ruleCheckStatus Decisions component after the soft delete reaches completed. After validation passes, it triggers the pluginHardDelete Plug-In component.
Add a Button component to
fgUIafterbtnDelete.Configure the following settings:
Setting
Value
Property ID
btnHardDeleteLabel
Permanently DeleteAction
Validate
Theme
Danger
Initial State
Disabled
Under Triggers, set the On Validation Success drop-down to
pluginHardDelete.
Configure startDate
The startDate Date Input lets the Creator specify the start of the date range. The pluginDelete Plug-In component and the pluginHardDelete Plug-In component read its value as dateFieldStartToFilterOn.
Add a Date Input component to
fgUIafter the buttons.Configure the following settings:
Setting
Value
Property ID
startDateLabel
Start Date (created after)Required
ON
Configure endDate
The endDate Date Input lets the Creator specify the end of the date range. The pluginDelete Plug-In component and the pluginHardDelete Plug-In component read its value as dateFieldEndToFilterOn.
Add a Date Input component to
fgUIafterstartDate.Configure the following settings:
Setting
Value
Property ID
endDateLabel
End Date (created on/before)Required
ON
Configure initError
The initError Initializer component sets the response field to Fail when something goes wrong. Both delete Plug-Ins reference it as their error handler.
Add an Initializer component to
fgConfig.Configure the following settings:
Setting
Value
Property ID
initErrorTrigger Type
Manual
Configure the Outputs:
#
Property ID
Type
Value
1
responseValue
Fail
Configure pluginDelete
The pluginDelete Plug-In component calls the Delete endpoint to archive records in the selected date range (soft delete). It is triggered by the btnDelete Button component. On success, it triggers the pluginGetJobDetails Plug-In component to begin polling.
Add a Plug-In component to
fgConfig.Configure the following settings:
Setting
Value
Property ID
pluginDeleteTrigger Type
Manual
Endpoint URL
https://{environment}.unqork.io/fbu/uapi/bulkOperations/deleteMethod
POST
Configure the Inputs:
#
Property ID
Value
1
resourceId'REPLACE_WITH_DATA_MODEL_ID'2
name'Bulk Delete'3
dateFieldToFilterOn'created'4
dateFieldStartToFilterOnstartDate5
dateFieldEndToFilterOnendDateConfigure the Outputs:
#
Property ID
Value
1
jobIdidUnder Triggers, set the Post Trigger drop-down to
pluginGetJobDetailsand the Error Handler drop-down toinitError.
To delete records from a previous Export operation instead, set
dataSourceto'EXPORT'and includeexportOperationIdas an additional input. See Bulk Data Operations for all available parameters.
Configure pluginHardDelete
The pluginHardDelete Plug-In component permanently removes all archived records in the same date range. It is triggered by the btnHardDelete Button component after the soft delete completes, and targets ARCHIVED records to avoid affecting active records.
Add a Plug-In component to
fgConfigafterpluginDelete.Configure the following settings:
Setting
Value
Property ID
pluginHardDeleteTrigger Type
Manual
Endpoint URL
https://{environment}.unqork.io/fbu/uapi/bulkOperations/delete?destroy=trueMethod
POST
Configure the Inputs:
#
Property ID
Value
1
resourceId'REPLACE_WITH_DATA_MODEL_ID'2
name'Bulk Hard Delete'3
targetRecordType'ARCHIVED'4
dateFieldToFilterOn'created'5
dateFieldStartToFilterOnstartDate6
dateFieldEndToFilterOnendDateConfigure the Outputs:
#
Property ID
Value
1
jobIdidUnder Triggers, set the Post Trigger drop-down to
pluginGetJobDetailsand the Error Handler drop-down toinitError.
Hard delete is permanent. Unqork cannot recover records after this step completes.
Configure pluginGetJobDetails
The pluginGetJobDetails Plug-In component checks the status of the current delete job. It is triggered by both the pluginDelete Plug-In component and the pluginHardDelete Plug-In component on success, and by the btnRefresh Button component when the Creator clicks it manually. On completion, it triggers the ruleCheckStatus Decisions component.
Add a Plug-In component to
fgConfigafterpluginHardDelete.Configure the following settings:
Setting
Value
Property ID
pluginGetJobDetailsTrigger Type
Manual
Endpoint URL
https://{environment}.unqork.io/fbu/uapi/bulkOperations/jobs/{{data.jobId}}Method
Configure the Outputs:
#
Property ID
Value
1
statusdata.statusUnder Triggers, set the Post Trigger drop-down to
ruleCheckStatus.
All BDO endpoints in this module use the
bulkOperations(camelCase, no hyphen).
Configure ruleCheckStatus
The ruleCheckStatus Decisions component reads the job status from the pluginGetJobDetails Plug-In component, triggers a pop-up message, and enables the btnRefresh Button component while a job is running. When the soft delete reaches completed, it also enables the btnHardDelete Button component so the Creator can proceed to the permanent delete.
Add a Decisions component to
fgConfigafterpluginGetJobDetails.Configure the following settings:
Setting
Value
Property ID
ruleCheckStatusTrigger Type
Manual
Configure the Inputs:
#
Property ID
Alias
Type
1
jobIdAExact
2
statusExact
Configure the Outputs:
#
Property ID
Type
1
btnRefreshDisabled
2
btnHardDeleteDisabled
3
fgUIPop Message
Add row per job status in the Decision grid:
Status
btnRefresh_disabledbtnHardDelete_disabledfgUI_popMessagecreated=IF(LEN(A)>0,'no','yes')yesDelete started.inProgress=IF(LEN(A)>0,'no','yes')yesDelete in progress.completed=IF(LEN(A)>0,'no','yes')noRecords archived. Click Permanently Delete to remove them, or leave them archived.partiallyCompleted=IF(LEN(A)>0,'no','yes')yesDelete partially complete.canceled=IF(LEN(A)>0,'no','yes')yesDelete canceled.failed=IF(LEN(A)>0,'no','yes')yesDelete failed.The formula in the disabled column uses
A(thejobIdalias).btnHardDeleteis set to a literalyes(always disabled) for all rows exceptcompleted, where it is set tono.
Test the Module
Open the module in Preview.
Enter a Start Date and End Date to define the range of records to delete.
Click Delete Records to begin the soft delete.
Click Refresh until the pop-up message reads
Records archived. Click Permanently Delete to remove them, or leave them archived.Open the submission using the platform's submission inspection method. See Debugger for how to access submission data from Express View.
Confirm the
jobIdandstatusfields contain the expected values.To permanently remove the archived records, click Permanently Delete.
Click Refresh again until the pop-up message updates to confirm the hard delete is complete.
Step 7 is irreversible. proceed if you are certain the archived records should be permanently removed.
Changelog
Date | Change |
|---|---|
2026-10-06 | Set btnDelete and btnHardDelete Action to Validate; added Required ON to startDate and endDate; corrected startDate label from "created on/after" to "created after" to match exclusive API behavior; updated bundle to match (EN-8164). |
2026-10-06 | Full restructure from tested POC: added startDate/endDate Date Input components, corrected pluginHardDelete to use targetRecordType ARCHIVED and dynamic date fields, fixed URLs to bulkOperations (camelCase), per-component Configure sections, Inputs/Outputs tables, bundle download link (EN-8164). |
2026-09-30 | Initial publication (EN-8164). |