The Data editor is a spreadsheet-style bulk tool for building and correcting your Organizational and Functional Structure — org units, Job Descriptions, Positions — and your people, all in one place. Instead of opening each screen one at a time, you work across all four in a single grid — type into cells, add and delete rows, and review every change before anything touches the database.
/{slug}/app/data-editor — sidebar Structure → Data editor.
The four tabs
| Tab | What it edits |
|---|---|
| Org structure | Org units — name, type, parent unit. Mirrors the tree in Org chart. |
| Job descriptions | Job Descriptions — the full record: name, purpose, job type, sub-sector and job family, work location, reporting line, qualifications, headcount, salary, Saudization priority, and its technical and general competencies. A handful of columns show in the grid; open a row's record panel (the expand button) to edit every field, grouped into sections. The grade code is shown read-only; system/workflow fields (version, approval status, SSCO code, grade rank) aren't exposed here. |
| Positions | Positions — title, the Job Description it belongs to, the org unit it sits in, seat capacity, measurement mode and hiring pathway. |
| People | People — name, current Position, manager, and the full contact & workforce record (four-part name, phone, profile links, start and birth dates, experience breakdown, mentoring flag). |
Each tab's label carries a small badge with the number of pending changes on that tab, so you can see at a glance where your edits are before you save.
Everything is staged until you save
Nothing you type is written to the database as you go. Every add, edit and delete is held locally in the browser — the grid, the tab badges and the row colors all reflect this local draft. Nothing reaches the server until you deliberately open the save summary and confirm (see Saving below).
Your draft is autosaved to this browser as you work. If you refresh or close the tab before saving, reopening the editor offers a choice — Continue editing (restores every staged change and your undo history exactly as you left them) or Start fresh (discards the draft and loads the current saved data). The draft still lives only in this browser and is never sent to the server until you save, and it's cleared automatically once a save succeeds.
Adding, editing and deleting a row
- Add row (in the toolbar) adds a blank row to whichever tab is active, pre-filled with sensible defaults. New rows carry a temporary id until they're saved — you can immediately reference a new row from another tab (for example, place a newly-added Position under a newly-added org unit) before either has a real database id.
- Edit any cell directly in the grid — text fields, dropdowns and number fields are all inline. See Constrained fields below for how relationships work.
- Delete a row with its row action. A deleted row is not removed from the grid immediately — it's struck through and marked Deleted so you can see exactly what will disappear, and you can undo it like any other change. Every row is deletable: if the row is linked to others, deleting it opens a short prompt asking how to handle the dependents — see Deleting a linked row.
Row status
Every row carries a colored status dot so you always know what's staged. If you forget which color is which, the info button next to the column-customization control opens a color legend:
| Status | Meaning |
|---|---|
| Added (green dot) | A new row created in this session, not yet saved. |
| Edited (amber dot) | An existing row with at least one changed field. |
| Deleted (red dot, row struck through) | Staged for deletion. Still visible so you can review or undo it before saving. |
| (no dot) | Unchanged — matches what's currently saved. |
A field with an invalid value is outlined and blocks saving until it's fixed or the row is discarded — see Validation.
Selecting rows and bulk actions
For repetitive changes you can act on many rows at once instead of one at a time.
- Select rows with the checkbox at the start of each row. The checkbox in the header selects — or clears — every row currently shown, so searching or filtering first and then select-all scopes the selection to just those rows.
- Once one or more rows are selected, an action bar appears above the grid showing the count and two bulk actions:
- Duplicate clones each selected row as a new Added row — a fresh copy you can then tweak. Handy for spinning up several near-identical positions or units.
- Delete stages every selected row for deletion at once. Bulk delete only handles clean rows: if your selection includes even one row that's linked to others, the Delete button is disabled — resolve that row individually (cascade or orphan) instead. This keeps a bulk delete from silently making a sweeping cascade decision for you.
- Clear (the ✕) drops the selection without changing anything.
Both bulk actions count as a single undo step — one Undo reverses the whole batch. Selection is per-tab and clears when you switch tabs, and deleted rows can't be selected. As always, nothing is written until you save.
Constrained fields: dropdowns, not free text
Relationship fields — an org unit's parent, a Job Description's sub-sector, a Position's org unit and Job Description, a person's current Position and manager — are dropdowns, never free text. You can only point a relationship at a row that genuinely exists: either already saved, or staged in this same draft (including a row you just added with Add row two seconds ago, even though it doesn't have a real id yet). This is what makes it safe to build a structure top-down in one sitting — add the org unit, then immediately add Positions under it, then people into those Positions — without ever typing an id or leaving a dangling reference.
The record panel: editing every field of a row
The grid deliberately shows only a lean set of columns so rows stay readable. To fill in every field of a row, click the expand button at the start of the row — a record panel opens on the side with the complete field set, laid out as a form grouped into sections (for a Job Description: Identity, Purpose & scope, Qualifications, Headcount & pay, Classification, and Competencies).
Edits in the panel behave exactly like edits in the grid — same staging, same undo/redo, same validation, same autosaved draft — the panel is just a roomier way to reach the fields that aren't shown as columns. You can still reveal any of those fields as a grid column from the Columns menu when you'd rather edit it across many rows at once.
The grade code appears read-only (it's the row's stable handle). System/workflow fields — version, approval status, SSCO code, grade rank, and the like — aren't editable here and aren't shown, so you can't accidentally disturb the sign-off and pay logic that maintains them.
Changing a Job Description's sub-sector, job family, or competencies
Sub-sector and job family are editable (as dropdowns), and a JD's technical and general competencies are editable too — each is a cell holding a semicolon-separated list of competency codes, with autocomplete offering the competencies allowed for the JD's job family. Competencies must belong to the JD's job family: an unknown code, or one outside the family, flags the row until you fix it.
Because a Job Description's competencies are anchored to its job family, moving a JD to a different family reconciles its competencies to the new family's set on save — unless you have curated the competencies yourself, in which case your explicit selection wins. Leaving the competencies cell untouched while re-parenting inherits the new family's defaults (never the old family's stale competencies); clearing the cell removes the family-scoped competencies. The job-family dropdown only lists families that belong to the chosen sub-sector and that your workspace has selected, so you can't create an unlinked pair; if a saved pair is ever invalid, the row is flagged until you fix it. Pay grade and competency proficiency levels still live on the Job Descriptions screen.
Undo and redo
The editor keeps a global, 10-step undo/redo history across all four tabs, not per tab. Undo (⌘/Ctrl+Z) and redo (⌘/Ctrl+Shift+Z) step through your last ten staged operations in order, and the toolbar shows up to ten dots that fill in as you make changes so you always know how much history is left. If undoing or redoing lands on a row in a different tab than the one you're viewing, the editor switches tabs for you and briefly highlights the row, so you never lose track of what just changed.
Undo/redo only affects the local draft — once you've saved, deletions and edits are final (see Saving).
Deleting a linked row
Every row can be deleted — but when a row still has things depending on it, deleting it opens a prompt so you decide what happens to those dependents rather than silently leaving a dangling reference. Dependents come in two kinds:
- In-grid dependents — rows you can see in the editor: an org unit's child units and Positions, a Job Description's Positions, a Position's people, a person's direct reports.
- Records managed elsewhere — data that depends on the row but isn't edited in this grid: a Position's hiring pipelines and interview rubrics, or a person's competency profile, growth plan, assessment history, pipeline entries, project memberships and documents. These are counted from the server when the page loads.
The prompt offers up to three choices:
- Cascade delete — delete the row and its whole dependent chain. Deleting a Job Description this way also deletes its Positions and the people in them, all the way down; the prompt shows how many rows will go. When the row also has records managed elsewhere, cascade removes those too — permanently — and the prompt warns you before you confirm. (For a person or Position this also clears related records such as credentials, employee profile and development history.) A Position whose openings have applications can't be deleted from the editor: the save is refused for that row, so deal with those applications in Hire first.
- Delete & orphan — delete only this row and unlink its in-grid dependents (their link back to it is cleared; they stay). Offered only when there's nothing managed elsewhere to worry about, since those hidden links can't be cleared from the grid.
- Cancel — leave everything as it is.
Nothing happens until you save — a cascade or orphan is staged like any other change and can be undone first.
Search and filter
Each tab has its own search box and filters, scoped to that tab only — filtering never hides or drops a staged change, it only changes what's visible:
- Search matches against that tab's text fields (names, titles).
- Status filter narrows to All / Invalid (needs fixing) / Added / Edited / Deleted / Unchanged. Invalid jumps straight to the rows that fail validation — the quickest way to find and fix everything blocking a save, especially after an import.
- Positions and People also get relation quick-filters (by org unit / Job Description for Positions, by Position for People).
Arranging the grid: column order, widths and visibility
Each tab's grid can be arranged to suit what you're working on, and your layout is remembered per tab in this browser:
- Reorder a column by dragging its header (grab the grip handle next to the column name) and dropping it onto another column. The Status and row-action columns stay pinned in place.
- Resize a column by dragging the divider on its trailing edge — widen a name column to read long titles, or narrow the ones you're not focused on. The Status and row-action columns stay fixed.
- Show or hide columns from the Columns menu (the gear button beside the search bar). Untick a column to hide it from view and retick to bring it back — this only changes what you see; hidden columns are never dropped from a staged edit or from the save.
- Created is a read-only timestamp column showing when each row was first created. It's hidden by default — turn it on from the Columns menu when you need it.
- Reset columns in the same menu restores every column to its default order, width and visibility.
Column order, widths and hidden columns are saved locally per tab, so switching between tabs — or reloading — keeps each grid the way you left it.
Excel export & import (round-trip)
For big batches it's often faster to work in Excel, then bring the changes back. The Export Excel and Import Excel buttons in the toolbar do exactly that — and unlike the older create-only importers, this is a true round-trip: it edits existing rows rather than duplicating them.
Export a template of your current data
Export Excel downloads a workbook with one sheet per tab (Org structure, Job descriptions, Positions, People), pre-filled with everything currently on screen — including any edits you've already staged. This is the template: fill it, don't start from a blank one.
Each sheet has two special leading columns you should not retype:
- An ID column (tinted grey) — the row's stable match key. Leave it exactly as-is; it's how the import knows which existing row you're editing.
- A code column where the entity has one — org unit code, JD grade code, employee number. A code is used to match first (when it's filled and unique); otherwise the ID is used.
The workbook carries every editable field of all four tabs — not just the columns shown in the grid. That means the full JD record (qualifications, work location, reporting line, and its technical/general competencies), every Position field (measurement mode, hiring pathway), and the complete People record (four-part name, phone, profile links, start/birth dates, experience breakdown, mentoring flag) all round-trip through Excel. System/workflow fields (JD version, approval status, SSCO code, grade rank; internal timestamps and plumbing) are deliberately left out of the file entirely.
- Relationship cells (parent unit, a Position's Job Description and org unit, a person's Position and manager, and a Job Description's sub-sector and job family) show a readable
Name ⟦id⟧value with a dropdown of valid targets. On import you can also just type a name — it's matched back to the right row (by id first, then by name) — so you don't have to keep the id intact. - Enum fields (type, status, gender, Saudization priority, measurement mode, hiring pathway…) are dropdowns; Yes/No fields (e.g. can-mentor) use a true/false dropdown; date fields take a
YYYY-MM-DDvalue. - Competency cells hold a semicolon-separated list of competency codes (
code; code). Each code must be a real competency in the JD's job family — the import validates them (see below).
Import the edited file
Import Excel reads the file back and matches each row to your current data by code, then ID:
- A row whose ID/code matches an existing row and whose values differ → staged as an edit.
- A row with a blank ID → staged as a new row (you can add rows straight in Excel; a new row can even reference another new row by its name).
- A row that exists now but is missing from the file → staged for deletion. This "treat missing rows as deletions" behaviour is a checkbox on the import dialog (on by default); untick it to only add and edit and never delete. An import can't prompt you row by row, so deletes that would orphan or cascade a record are automatically skipped and reported — delete those rows individually from the grid, where you're offered cascade or orphan.
The import never writes to the database directly. It stages the changes into the same draft as manual edits — you land back in the grid with the usual green/amber/red row chips and tab badges, review everything, and then Save as normal. A single Undo reverts an entire import at once.
Imported rows are validated on the way in. Every staged row is checked the same way a hand-edited one is — required fields, number and date shapes, valid dropdown values, and relationship integrity: a JD's sub-sector/job-family pair must be linked, and every competency code must resolve to a real competency that belongs to that job family. Any row that fails is flagged (the offending cell is outlined in red with a message) and Save stays blocked until it's fixed — so a corrupted file can never be committed. Use the Invalid status filter to jump straight to the rows that need attention. Cells the import couldn't interpret (an unmatched relationship name, a non-numeric number) are reported as warnings and left unchanged rather than overwriting good data.
Saving: a change summary, then one confirmation
Save in the toolbar is disabled until there's at least one staged change, and stays disabled while any row has a validation error. Clicking it opens the Save summary — a table with one row per tab (Org structure, Job descriptions, Positions, People) and a column each for Added / Edited / Deleted, plus a grand total. If any deletions are staged, a warning notes that deletions are permanent and cannot be undone once saved — undo only works on the local draft, not after the commit.
Confirm & Save applies everything in one transaction:
- New rows across all four tabs are created and their temporary ids are resolved to real ones — so a Position you added pointing at a newly-added org unit gets wired to that unit's real id automatically.
- Edits and deletions apply together with the adds, in the scope you reviewed — nothing partial.
- If the underlying data changed on the server since you loaded the page (someone else edited the same workspace), the save is refused with a stale data notice instead of silently overwriting their changes; reload to get the current state (this discards your local draft).
- If specific rows fail validation server-side, the dialog lists exactly which ones and why, and switches you to the first affected tab so you can fix them and retry.
On success, the editor reloads fresh data from the server and the draft — and its undo history — starts clean.
Validation
Beyond the dropdown constraints above, each field has shape rules (required fields, valid number ranges, well-formed dates) and relationship-integrity rules — the same checks whether you typed the value in the grid or brought it in from Excel:
- Required columns are marked with a red asterisk (*) in their header, so you can see what must be filled before you start typing.
- A cell with a missing required value, an invalid value, or a broken relationship is outlined in red with a message. Relationship checks include a JD's sub-sector/job-family pair (must be linked) and its competencies set (every competency must be a real competency in that job family — an unknown or out-of-family competency flags the row).
- Whenever any row still has such an error, a warning icon appears at the top of the toolbar — hover (or focus) it for a plain-language reminder — and Save stays disabled across every tab until every row is valid. The Invalid status filter lists exactly those rows so you can fix them fast.
Fix the highlighted field or discard the row to clear the error. If a row still fails validation server-side when you save, the Save summary lists exactly which rows and why.
Related
- Job Descriptions & Positions — the full model behind two of the editor's tabs, including taxonomy, salary grade, and hiring fields not editable here.
- Org chart — the visual, drag-and-drop view of the org structure the first tab edits.
- Roles and permissions — who can view vs. save changes in the editor.