# Module Builder Tasks

The Module Builder provides a drag and drop interface for creating small dashboard modules without writing code. Open the **Module Builder** card from the dashboard to access the tool. Three sections are displayed:

- **Components** – palette of available items
- **Canvas** – drop area for arranging components
- **Properties** – inspector for the selected item

## Creating a Module

1. Drag components from the palette onto the canvas.
2. Click an item to edit its name, placeholder text and other properties.
3. Use **Export** to download the configuration as JSON. Importing the JSON rebuilds the same layout.

Buttons can be configured to open a form or trigger a workflow event. Selecting a table allows you to choose a synced table name so the DataLoader populates headers automatically. Tabs support adding and renaming panels on the fly.

## Editing Existing Modals

Use the Module Builder route with a modal `id` parameter to edit existing definitions from the `ui_modals` table. Loading a modal this way prepopulates the builder so you can make changes and save the updated configuration for all users.

## Component Types

The palette is grouped into categories with these options:

- **Buttons** – `button` (can call forms or workflows)
- **Tabs** – `tabs-basic` with dynamic tab creation
- **Tables** – `table` with DataLoader integration
- **Graphs** – `graph-map`, `graph-chart`, `fishbone-diagram`, `graph-d3`
- **Inputs** – `input-text` and `select-basic`

Drop items to nest them (such as placing buttons in tab panels). Each component stores settings in `data-` attributes so configurations export cleanly.

Table components now expose **Scope** and **User Field** fields. Set `Scope` to `all`, `admin_user` or `user` to control automatic filtering. When a user field is provided the DataLoader limits rows to the current user unless the viewer is an admin and `admin_user` was selected.


## Documents Widget

Drag the **documents** component onto the canvas to display a table of uploaded files and an upload area. When the module runs, `DocumentsWidget` loads the records using `LocalSyncManager` and refreshes the table whenever a new file is uploaded.

Use the **Scope** property to select whether the widget shows tenant or user documents. A `folder_id` or `category_id` can be specified to limit files to a particular workspace or category.

### Linking Filters

Add a **filter-select** component anywhere in the modal to drive filtering for tables or widgets. Set the component's `data_column` property to match the field name on the target element.
Body components such as tables, the calendar, Kanban board and documents widget expose a `filterField` option. When this matches the filter's `data_column` the selected values are passed through the `builderFilterChanged` event and applied automatically. Choose **Multi Select** to allow selecting multiple IDs; selecting **All** clears the filter.

## Calendar Component

Adding the **calendar** component inserts a full page calendar backed by the
`calendar_events` table. When the module is loaded `Calendar.js` initialises a
FullCalendar instance and pulls events from the sync manager. Use the **Scope**
property to decide whether the calendar shows organisation events (`tenant`) or
only personal items (`user`). The **Filter Field** option accepts a column name
such as `branch_id` or `client_id` so filter dropdowns can drive which events
are displayed.
Setting `filterField="category_id"` allows a filter-select to choose which event
category is shown.

## Tasks Component

The **tasks** component renders the Workflow Tasks list using the
`WorkflowTasks` module. It displays tasks assigned to the current user and
supports the same filtering mechanism as other widgets. Setting the component's
`filterField` lets a dropdown control which tasks are shown &ndash; for example,
filtering by `board_id` or `assignee_id`.

## Fishbone Diagram

The **fishbone-diagram** component draws a cause-and-effect diagram stored in
the `fishbone_diagrams` table. Select a diagram from the **Diagram** dropdown in
the properties panel. The widget renders an SVG showing the problem statement
and each category branch. Diagrams can be created and edited through the
**Fishbone Diagram Manager** modal.

The diagram expands to the width of its container by default. Optional `width`
and `height` values can override the calculated size.

Create diagrams by posting JSON to `/api/fishbone_diagrams` with `problem` and
`categories` fields. Use the returned `id` as `diagramId` when adding a
`fishbone-diagram` body element in Module Builder or Detail View Builder. See
[docs/FishboneDiagram.md](FishboneDiagram.md) for editor usage.

## Fault Tree Diagram

The **fault-tree-diagram** component visualizes failure logic stored in the
`ohs_fault_trees` table. Use the **Fault Tree Manager** modal to create or edit
diagrams. Include `{ "type": "fault-tree-diagram", "options": { "diagramId": 1 } }`
in a module body to render a saved tree.

## Five Whys

Use the **Five Whys Manager** card on the dashboard to document repeated "why" questions when investigating an incident. The modal saves rows in the `ohs_five_whys` table through `LocalSyncManager`, so `/api/sync` and `SyncController` handle the CRUD logic. See [docs/FiveWhys.md](FiveWhys.md) for details.

## D3 Graph

The **graph-d3** component renders a scatter plot defined with the Graph Builder.
Select a saved graph from the **Graph** dropdown. ModalBuilder fetches the
configuration from `/api/graphs/{id}` and draws it using D3 when the modal opens.

## Filter Dropdown

The **filter-select** component builds a dropdown from a table column. Set its
`source_table` and `source_column` properties to load options through the sync
manager. The `data_column` property determines the name passed to
`builderFilterChanged` when the value changes. Any body element with a matching
`filterField` receives the selected values and applies them to its DataLoader or
widget instance.

Filter dropdowns listen for `tableUpdated` and `tableSynced` events on their
`source_table`. `tableUpdated` now includes `{ tableName, action, record }`
so the dropdown can add or modify a single option without reloading every
value. When only the table name is provided, or after a full sync, the
component reloads all options to ensure the latest values appear without
reopening the modal.

Additional fields:

- **display_column** – column used for the option text. Defaults to `source_column`.
- **default_label** – text for the blank option shown at the top.

### Linking to Specific Resources

1. Place a filter-select in the module header and set
   `data_column` to the field used by the target component
   (for example `folder_id`, `category_id`, `board_id` or `branch_id`).
2. Set the target component's `filterField` property to the same name.
3. Optionally preselect values in the filter-select to bind the module to a
   particular folder, calendar or board when it first opens.

Example usage:

```json
{
  "type": "filter-select",
  "options": {
    "source_table": "clients",
    "source_column": "id",
    "data_column": "client_id",
    "multi_select": true
  }
}
```

With the above filter in place a documents widget configured with
`filterField="client_id"` will show files only for the selected clients. The
multi-select option allows choosing several clients at once. Setting `scope` to
`tenant` on the documents or calendar components restricts the data to the
current organisation.
