Filter to active items only, remove Status column, document widget binding rules
- Add WHERE item_active filter to show only active unused items - Remove Status column from query and table widget - Add widget binding guidance to AGENTS.md (NUMBER inputs cannot use NULLIF pattern due to prepared statement typing) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
16
AGENTS.md
16
AGENTS.md
@@ -101,10 +101,24 @@ Every `widgetId` across all pages must be globally unique. Use short descriptive
|
||||
- SQL source of truth: `<query_name>.txt` (readable, real newlines).
|
||||
- `metadata.json` `body` field: same SQL but JSON-escaped (`\n`, `\"`).
|
||||
- Table binding: `{{query_name.data}}`.
|
||||
- Optional date filter pattern: `NULLIF('{{Widget.selectedDate}}','') IS NULL OR ... BETWEEN ...::date AND ...::date`.
|
||||
- All production queries use `xTuple_GoLive` datasource.
|
||||
- **Database credentials are managed by Appsmith server-side** — they are not stored in this repository. The datasource JSON only contains the name and plugin reference. When developing/testing SQL queries locally, use separate read-only credentials provided by the user — never embed them in committed files.
|
||||
|
||||
### Widget Bindings in SQL (IMPORTANT)
|
||||
|
||||
Appsmith uses prepared statements (`pluginSpecifiedTemplates[0].value = true`). When a query body contains `{{Widget.property}}`, Appsmith replaces each binding with a typed prepared statement parameter (`$1`, `$2`, etc.).
|
||||
|
||||
**For DATE_PICKER_WIDGET2** (text/date type parameters):
|
||||
- The `NULLIF` pattern works: `NULLIF('{{DateWidget.selectedDate}}','')::date`
|
||||
- This is safe because the parameter is always typed as `text`.
|
||||
|
||||
**For INPUT_WIDGET_V2 with `inputType: "NUMBER"`** (integer type parameters):
|
||||
- Do **NOT** use `NULLIF('{{Widget.text}}','')::int` — this fails because Appsmith may type the parameter as `integer`, and `NULLIF(integer, '')` causes a type mismatch error (`invalid input syntax for integer: ""`).
|
||||
- Instead, use a direct cast: `'{{Widget.text}}'::int`
|
||||
- The widget's `defaultText` property ensures there is always a value on page load, so NULL/empty handling is unnecessary.
|
||||
|
||||
**General rule**: Match the SQL cast to the widget's output type. When in doubt, test with a hardcoded value first to confirm the base query works, then add the binding.
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Add a new page
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"pluginType": "DB",
|
||||
"unpublishedAction": {
|
||||
"actionConfiguration": {
|
||||
"body": "SELECT\n i.item_number AS \"Item Number\",\n i.item_descrip1 AS \"Description\",\n CASE i.item_type\n WHEN 'P' THEN 'Purchased'\n WHEN 'M' THEN 'Manufactured'\n WHEN 'R' THEN 'Reference'\n WHEN 'T' THEN 'Tooling'\n WHEN 'O' THEN 'Outside Process'\n WHEN 'B' THEN 'Breeder'\n WHEN 'C' THEN 'Co-Product'\n WHEN 'F' THEN 'Phantom'\n ELSE i.item_type\n END AS \"Item Type\",\n CASE WHEN i.item_active THEN 'Active' ELSE 'Inactive' END AS \"Status\",\n cc.comment_user AS \"Created By\",\n COALESCE(i.item_created, cc.comment_date)::date AS \"Date Created\",\n last_txn.last_transaction_date::date AS \"Last Transaction\",\n (CURRENT_DATE - COALESCE(last_txn.last_transaction_date, i.item_created, cc.comment_date)::date) AS \"Days Unused\"\nFROM item i\nLEFT JOIN comment cc\n ON cc.comment_source_id = i.item_id\n AND cc.comment_source = 'I'\n AND cc.comment_text = 'Created'\nLEFT JOIN (\n SELECT\n isite.itemsite_item_id,\n MAX(ih.invhist_transdate) AS last_transaction_date\n FROM itemsite isite\n JOIN invhist ih ON ih.invhist_itemsite_id = isite.itemsite_id\n GROUP BY isite.itemsite_item_id\n) last_txn ON last_txn.itemsite_item_id = i.item_id\nWHERE (CURRENT_DATE - COALESCE(last_txn.last_transaction_date, i.item_created, cc.comment_date)::date)\n >= '{{UnusedDays.text}}'::int\nORDER BY \"Days Unused\" DESC",
|
||||
"body": "SELECT\n i.item_number AS \"Item Number\",\n i.item_descrip1 AS \"Description\",\n CASE i.item_type\n WHEN 'P' THEN 'Purchased'\n WHEN 'M' THEN 'Manufactured'\n WHEN 'R' THEN 'Reference'\n WHEN 'T' THEN 'Tooling'\n WHEN 'O' THEN 'Outside Process'\n WHEN 'B' THEN 'Breeder'\n WHEN 'C' THEN 'Co-Product'\n WHEN 'F' THEN 'Phantom'\n ELSE i.item_type\n END AS \"Item Type\",\n cc.comment_user AS \"Created By\",\n COALESCE(i.item_created, cc.comment_date)::date AS \"Date Created\",\n last_txn.last_transaction_date::date AS \"Last Transaction\",\n (CURRENT_DATE - COALESCE(last_txn.last_transaction_date, i.item_created, cc.comment_date)::date) AS \"Days Unused\"\nFROM item i\nLEFT JOIN comment cc\n ON cc.comment_source_id = i.item_id\n AND cc.comment_source = 'I'\n AND cc.comment_text = 'Created'\nLEFT JOIN (\n SELECT\n isite.itemsite_item_id,\n MAX(ih.invhist_transdate) AS last_transaction_date\n FROM itemsite isite\n JOIN invhist ih ON ih.invhist_itemsite_id = isite.itemsite_id\n GROUP BY isite.itemsite_item_id\n) last_txn ON last_txn.itemsite_item_id = i.item_id\nWHERE i.item_active\n AND (CURRENT_DATE - COALESCE(last_txn.last_transaction_date, i.item_created, cc.comment_date)::date)\n >= '{{UnusedDays.text}}'::int\nORDER BY \"Days Unused\" DESC",
|
||||
"encodeParamsToggle": true,
|
||||
"paginationType": "NONE",
|
||||
"pluginSpecifiedTemplates": [
|
||||
|
||||
@@ -12,7 +12,6 @@ SELECT
|
||||
WHEN 'F' THEN 'Phantom'
|
||||
ELSE i.item_type
|
||||
END AS "Item Type",
|
||||
CASE WHEN i.item_active THEN 'Active' ELSE 'Inactive' END AS "Status",
|
||||
cc.comment_user AS "Created By",
|
||||
COALESCE(i.item_created, cc.comment_date)::date AS "Date Created",
|
||||
last_txn.last_transaction_date::date AS "Last Transaction",
|
||||
@@ -30,6 +29,7 @@ LEFT JOIN (
|
||||
JOIN invhist ih ON ih.invhist_itemsite_id = isite.itemsite_id
|
||||
GROUP BY isite.itemsite_item_id
|
||||
) last_txn ON last_txn.itemsite_item_id = i.item_id
|
||||
WHERE (CURRENT_DATE - COALESCE(last_txn.last_transaction_date, i.item_created, cc.comment_date)::date)
|
||||
WHERE i.item_active
|
||||
AND (CURRENT_DATE - COALESCE(last_txn.last_transaction_date, i.item_created, cc.comment_date)::date)
|
||||
>= '{{UnusedDays.text}}'::int
|
||||
ORDER BY "Days Unused" DESC
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
"Item Number",
|
||||
"Description",
|
||||
"Item Type",
|
||||
"Status",
|
||||
"Created By",
|
||||
"Date Created",
|
||||
"Last Transaction",
|
||||
@@ -57,7 +56,6 @@
|
||||
{"key": "primaryColumns.Item Number.computedValue"},
|
||||
{"key": "primaryColumns.Description.computedValue"},
|
||||
{"key": "primaryColumns.Item Type.computedValue"},
|
||||
{"key": "primaryColumns.Status.computedValue"},
|
||||
{"key": "primaryColumns.Created By.computedValue"},
|
||||
{"key": "primaryColumns.Date Created.computedValue"},
|
||||
{"key": "primaryColumns.Last Transaction.computedValue"},
|
||||
@@ -187,37 +185,6 @@
|
||||
"verticalAlignment": "CENTER",
|
||||
"width": 150
|
||||
},
|
||||
"Status": {
|
||||
"alias": "Status",
|
||||
"allowCellWrapping": false,
|
||||
"allowSameOptionsInNewRow": true,
|
||||
"columnType": "text",
|
||||
"computedValue": "{{(() => { const tableData = Table1.processedTableData || []; return tableData.length > 0 ? tableData.map((currentRow, currentIndex) => (currentRow[\"Status\"])) : [] })()}}",
|
||||
"currencyCode": "USD",
|
||||
"decimals": 0,
|
||||
"enableFilter": true,
|
||||
"enableSort": true,
|
||||
"horizontalAlignment": "LEFT",
|
||||
"id": "Status",
|
||||
"index": 3,
|
||||
"isCellEditable": false,
|
||||
"isCellVisible": true,
|
||||
"isDerived": false,
|
||||
"isDisabled": false,
|
||||
"isDiscardVisible": true,
|
||||
"isEditable": false,
|
||||
"isSaveVisible": true,
|
||||
"isVisible": true,
|
||||
"label": "Status",
|
||||
"notation": "standard",
|
||||
"originalId": "Status",
|
||||
"sticky": "",
|
||||
"textSize": "0.775rem",
|
||||
"thousandSeparator": true,
|
||||
"validation": {},
|
||||
"verticalAlignment": "CENTER",
|
||||
"width": 150
|
||||
},
|
||||
"Created By": {
|
||||
"alias": "Created By",
|
||||
"allowCellWrapping": false,
|
||||
@@ -230,7 +197,7 @@
|
||||
"enableSort": true,
|
||||
"horizontalAlignment": "LEFT",
|
||||
"id": "Created By",
|
||||
"index": 4,
|
||||
"index": 3,
|
||||
"isCellEditable": false,
|
||||
"isCellVisible": true,
|
||||
"isDerived": false,
|
||||
@@ -261,7 +228,7 @@
|
||||
"enableSort": true,
|
||||
"horizontalAlignment": "LEFT",
|
||||
"id": "Date Created",
|
||||
"index": 5,
|
||||
"index": 4,
|
||||
"isCellEditable": false,
|
||||
"isCellVisible": true,
|
||||
"isDerived": false,
|
||||
@@ -292,7 +259,7 @@
|
||||
"enableSort": true,
|
||||
"horizontalAlignment": "LEFT",
|
||||
"id": "Last Transaction",
|
||||
"index": 6,
|
||||
"index": 5,
|
||||
"isCellEditable": false,
|
||||
"isCellVisible": true,
|
||||
"isDerived": false,
|
||||
@@ -323,7 +290,7 @@
|
||||
"enableSort": true,
|
||||
"horizontalAlignment": "LEFT",
|
||||
"id": "Days Unused",
|
||||
"index": 7,
|
||||
"index": 6,
|
||||
"isCellEditable": false,
|
||||
"isCellVisible": true,
|
||||
"isDerived": false,
|
||||
|
||||
Reference in New Issue
Block a user