Chapters Bulk Operations

Guide 09

Bulk Operations

Doing the same thing to hundreds of records: exporting a list, acting on a selection, and importing from a spreadsheet.

Updated

Every list page in Merak shares one batch engine, so what you learn here applies everywhere. This chapter is the reference; each feature chapter only notes what is different about it.

What you can do here

  • As an administrator, I want to export the list I have filtered, so that I can analyse or archive it offline.
  • As an administrator, I want to pick specific rows and act on all of them, so that repetitive work takes one action.
  • As an administrator, I want to create many records from a spreadsheet, so that onboarding a department is not a day of typing.
  • As an administrator, I want to update many existing records from a spreadsheet, so that a bulk change is one file, not one hundred edits.
  • As an administrator, I want to see exactly what was submitted for every row, so that I can prove what changed.

1. Where each capability exists

PageExportBatch actionsImport
MembersDeactivate · Activate · Unlock · Delete (with force recovery)
ApplicationsActivate · Deactivate · Delete
OrganizationsDelete
UsersDeactivate · Activate · Unlock · Delete
RolesDelete (system roles excluded)
Audit log— (read-only)
Connection log— (read-only)
ApprovalsApprove · Reject
Merak Nodes— (no multi-select)

Approvals deliberately has no export. Its rows carry request payloads, not a tabular record.


2. Export

2.1 Exporting everything the filter matches

  1. Open the Export button in the toolbar (grouped with Filter and Refresh).
  2. A dialog confirms that the export follows your current filter, and shows the total if it is known.
  3. Confirm.

What happens then:

  • The job joins a queue shared across all your browser tabs. If two tabs export at once, one runs and the other shows “queued” — the server is never asked for the same pages twice.
  • Rows are fetched 200 at a time.
  • Progress is indeterminate until the first page returns, then shows fetched / total.
  • The result downloads as CSV in UTF-8 with a BOM, so Excel opens Chinese correctly.

File names follow <domain>-YYYY-MM-DD.csv, for example members-2026-09-03.csv, roles-2026-09-03.csv, audit-logs-2026-09-03.csv.

2.2 Exporting only the rows you picked

  1. Tick rows.
  2. Open Review selection (N).
  3. Select Export selection.

The file is written locally from what is already on screen — no server request — and is named <domain>-selection-YYYY-MM-DD.csv.

Selection export carries only the base columns. Columns describing many-to-many relations — a member’s applications, a user’s roles, a role’s permissions — need an extra fetch per row, and a selected row is only a snapshot. Use the full export when you need those columns.

2.3 Relation columns and their permissions

Some exports include a relation column assembled per row, with values joined by ;:

ExportRelation columnRequired permissionWithout it
UsersRolesrole:RThe column is omitted entirely.
RolesPermissionspermission:RThe column is omitted entirely.
OrganizationsMembers, Applicationsmember:R / application:RThe column is omitted.

Merak does not fetch data for a column you may not read.

2.4 Export permissions

Export is gated by the page’s own read permission — if you can open the list, you can export it. No stricter gate is applied.


3. Selecting rows and acting on them

3.1 Selecting

  • Every list with batch actions has a checkbox column in front of each row.
  • The header checkbox covers the current page and shows three states: all, some, none.
  • A selection survives paging and re-sorting within the same search.
  • It is cleared when you start a new search (submit a filter, or reset). A background refresh does not clear it.

3.2 The selection toolbar

As soon as anything is ticked, the toolbar’s usual buttons (Filter, Refresh, Export, Import, Create) are replaced by two:

  • Clear all
  • Review selection (N)

3.3 The review dialog

Shows exactly what you have picked, from the snapshot already in the browser — no further requests. You can remove rows one by one; emptying the list closes the dialog.

At the bottom sit the available batch actions, plus Export selection.

3.4 How an action decides whether it is available

A batch action is enabled only when both are true:

  1. You hold the permission for it, and
  2. Every selected row satisfies its precondition.

If only some rows qualify, the button reads M/N eligible and offers Keep only eligible — one click trims the selection so the action becomes available. If you hold no permission for an action, it is not shown at all.

Preconditions in practice:

ActionPrecondition
Deactivate (member/user)Every row is Active
ActivateEvery row is Inactive
UnlockEvery row is Locked
Delete (member/user)Every row is Inactive / Pending / Locked
Delete (application)Every row is Inactive
Delete (role)Every row is not a system role
Approve / RejectEvery row is Pending

Roles are gated on isSystem up front rather than letting each system role fail one by one against the server — you find out before you run, not after.

3.5 Running the action

Rows are processed one by one with bounded concurrency. A single failure never aborts the batch. When it finishes:

OutcomeWhat you see
All succeededA success notification; the dialog closes; the selection clears.
Some failedThe dialog stays open with success and failure counts and a reason per failure. Successful rows are dropped from the selection automatically, leaving only the failures for a retry.

Batch jobs across multiple tabs go through the same shared queue as exports.

3.6 Force delete

Only members offer a force-delete recovery path when a delete is refused because the record is still in use. Applications, organizations, roles and users do not — a failed delete there is final until you clear the dependency yourself.


4. Import

Import gets its own full-page workspace, reached from the Import button in the list toolbar. It requires the resource’s create permission (C), and the modify mode requires update (U).

Route: /<resource>/import, for example /member/import, /role/import. The page header carries a back arrow and a breadcrumb back to the list.

4.1 Two modes

ModePurposeNeeds
CreateCreate new records.<resource>:C
ModifyUpdate existing records.<resource>:U

When you hold both permissions, a mode switch appears; the chosen mode is written into the URL, so a reload or a shared link keeps it. If you hold only one, that mode is used with no switch. You are sent back to the list only when you hold neither.

4.2 The workflow

Download template → fill it in → upload → parse & validate
        → preview and fix → submit → per-row result report

Step 1 — Download the template

The template is a CSV (UTF-8 with BOM) with localised headers and several example rows, assembled from your real data and your current language:

  • Enum columns use the localised labels.
  • Relation columns list names that actually exist in your tenant — and, for roles’ permissions, only ones you can grant. The examples can therefore be re-imported as-is.
  • Example rows cover the range of each column: every status, both switch positions, zero to three related items.

In modify mode the template is instead pre-filled with 1–10 randomly sampled existing records and every editable column, so an edit is a small diff rather than a fresh transcription. File names are <domain>-create-template.csv and <domain>-edit-template.csv.

If there is nothing to sample from, Merak tells you to create a record first rather than downloading an empty file.

Step 2 — Upload

Three ways in: choose a file, drag and drop, or paste directly from a spreadsheet. Parsing runs on a background thread and streams row by row, so the page stays responsive: first “parsing X rows…”, then a determinate “validating X / Y” bar.

Under the drop zone, a field guide panel explains every column: which are required, what an enum column accepts, which words count as on/off for a switch column, how to write multiple values, and — for relation columns — that the name must match the Console exactly.

Limit: 500 rows. A larger file blocks submission and asks you to split it.

Step 3 — Parse and validate

Validation happens in two layers.

Enum columns (statuses, protocol types) accept localised text. They are matched exactly first, then fuzzily — pinyin and small typos are tolerated — and only reported as an error when neither works.

Boolean columns accept a broad vocabulary in Chinese and English. Every boolean column understands the shared set:

MeaningAccepted words
Ontrue, 1, yes, y, on, enable, enabled, , 開啟, 啟用, 打開, 啟動
Offfalse, 0, no, n, off, disable, disabled, , 關閉, 停用, 停止

Individual columns may add their own words on top. The member import’s MFA Required column, for example, also accepts enforce, enforced, required, mandatory, 強制, 要求, 必須 for on and optional, not required, 不強制, , 非必要 for off — those extras are specific to that column, not part of the shared set.

The words in your file are independent of the Console’s display language.

Relation columns (a user’s roles, a role’s permissions, an organization’s members and applications) accept several values per record — either by repeating the header, or by separating them with ; inside one cell. Each value is a name, matched exactly; fuzzy matching is deliberately not used here, so a near-miss can never bind you to the wrong role or the wrong permission. Duplicates within a cell are de-duplicated automatically; a name that matches nothing is an error.

Row-level rules then apply the usual field validation — name length, email format, description length, and so on.

Step 4 — Errors and warnings

Two severities, and they behave differently.

SeverityMarkerBlocks submission
Error (hard)Red cell, error messageYes
Warning (soft)Amber dot, inline noticeNo

Things that are only warnings, on purpose:

  • A duplicate display name. The backend allows two people with the same name, because two people really can have the same name. The row stays valid and is counted under “N rows with notices”.
  • Two rows matching the same existing record in modify mode. Each row is flagged with “row N also updates this record” — the later submission wins. Two rows editing different columns of one record is legitimate use.

Things that are hard errors:

  • An unresolvable enum, boolean or relation value.
  • A failed field rule.
  • An illegal status transition. Status columns declare a state machine, and the preview’s status dropdown only offers reachable values. Import must not become a back door around the lifecycle.

Step 5 — Preview and fix

The preview is a virtualised list of every row, with counts of valid, invalid and auto-corrected rows, and a show errors only toggle.

Column typeEditor
EnumDropdown of the valid values.
BooleanLabelled switch.
RelationMulti-select with server-side search as you type. Selected items appear as tags; a name that resolved to nothing is a red tag.
TextInline text field.

You can also:

  • Apply a value to every row that shares the same original value.
  • Add a row by hand without touching the CSV. In create mode the new row is pre-filled from the rotating example set (so several new rows do not collide); in modify mode it is left blank, because a modify row is meant to locate an existing record, not invent one.
  • Append a second file. Dropping another CSV onto the preview area — or using Append import filemerges its rows into the batch instead of replacing them. Source data split by department or site does not have to be merged by hand first. The appended file is parsed up to the remaining row budget; going over is flagged rather than silently truncated, and a batch already at 500 rows refuses outright. If the appended file fails to parse, only that file is lost — the preview and your existing rows are untouched.
  • Delete rows.

Step 6 — Locating records (modify mode only)

A modify row must be matched to an existing record before it can be submitted.

  • Matching order varies by resource: ID first, then email, then name (users and members); ID then name (roles, organizations).
  • A stale key does not dead-end the row — edit any matching column to re-locate it.
  • Duplicate names are marked ambiguous and resolved through autocomplete.
  • A row that fails to match shows its imported values read-only and opens the matching columns for editing; a debounced autocomplete on name, email or ID pins the row as soon as it resolves to exactly one record.
  • Withdraw match un-pins a matched row without touching its data. The row returns to unmatched, the matching columns reopen and it drops out of the submission. Matching is deliberately not re-run while withdrawn — otherwise it would immediately re-pin the record you just rejected. Editing any matching key lifts the withdrawal and re-locates; Re-match does the same on demand.

Step 7 — What modify actually sends

Only columns that differ from the current value and are not blank are sent. A blank cell means “leave this alone”, never “clear this”. Where a column can be cleared deliberately, \N is the way to do it (for example an organization’s or a role’s description).

Two safety positions worth knowing:

  • Status and MFA-required columns have no default in modify mode. A blank cell is skipped, never applied. Import will not silently move an account to pending or switch off an MFA requirement.
  • Relation columns are hidden in modify mode. Set-style synchronisation is not offered yet — use the record’s own edit screen.

Step 8 — Submit

Each row is submitted individually with bounded concurrency, and a failed row does not stop the others.

Composition rules differ where a row creates a record and its relations:

ImportIf a relation write fails
UsersThe whole row fails. A user without their intended roles is not a useful result.
RolesThe row still succeeds. Only a failure to create the role itself fails the row.
OrganizationsAssociation failures are tolerated; only the organization itself failing fails the row.

Step 9 — The result report

The completion screen is a row-by-row report, not two numbers:

  • Row number, the record, and either success or the failure reason.
  • Failed rows are listed first.
  • View submitted data expands what that row actually sent. In modify mode it is shown as old value → new value, with a link to the record’s detail page. In create mode the new record’s ID is not available, so the link column is omitted rather than left blank.
  • Download failed rows produces a CSV of just the failures, ready to fix and re-import.
  • Back returns to the list.

Imports running in several tabs are serialised through the same shared queue as exports and batch actions.


5. Saved list preferences

Two per-list settings are stored in your browser and appear in Preferences.

5.1 Column settings

The gear in a table’s action column header opens a dialog where you can tick columns visible or hidden and drag them into a different order. The row-number column (always first) and the action column (always last) are fixed.

The setting is stored per browser and survives sign-out. Reset to default is available per table, here and in Preferences.

5.2 Default filters

In the filter panel, Save as default stores the conditions currently shown in the panel — including ones you have not submitted yet — on this machine, synced across tabs.

  • Next time you open the list with no filter parameters in the URL, the default is applied automatically and the panel opens.
  • A URL that already carries filters always wins, so an explicit query or a shared link is never overridden.
  • The automatic apply happens once per visit.
  • Clear default removes it, from the panel or from Preferences.

6. Permission summary

TaskPermission
Export a listthat list’s read permission
A relation column in an exportthat relation’s read permission (else the column is omitted)
A batch actionthe same permission as the single-row action
Enter and submit an import<resource>:C (create) / <resource>:U (modify)
Import a relation columnthat relation’s read permission

Next