Skip to content

Commit ac4126b

Browse files
#Added support for action buttons in the table component template.
* A default edit and delete button can be included by specifying an "edit_url" or "delete_url" * Custom Column based action buttons can be added in the table header using json object array in the custom_actions column. * Custom action buttons can be defined on the row level by specifying _sqlpage_actions.
1 parent 9a8bb78 commit ac4126b

2 files changed

Lines changed: 212 additions & 1 deletion

File tree

examples/official-site/sqlpage/migrations/01_documentation.sql

Lines changed: 167 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -810,11 +810,15 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S
810810
('money', 'Name of a numeric column whose values should be displayed as currency amounts, in the currency defined by the `currency` property. This argument can be repeated multiple times.', 'TEXT', TRUE, TRUE),
811811
('currency', 'The ISO 4217 currency code (e.g., USD, EUR, GBP, etc.) to use when formatting monetary values.', 'TEXT', TRUE, TRUE),
812812
('number_format_digits', 'Maximum number of decimal digits to display for numeric values.', 'INTEGER', TRUE, TRUE),
813+
('edit_url', 'If set, an edit button will be added to each row. The value of this property should be a URL, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row. Clicking the edit button will take the user to that URL.', 'TEXT', TRUE, TRUE),
814+
('delete_url', 'If set, a delete button will be added to each row. The value of this property should be a URL, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row. Clicking the delete button will take the user to that URL.', 'TEXT', TRUE, TRUE),
815+
('custom_actions', 'If set, a column of custom action buttons will be added to each row. The value of this property should be a JSON array of objects, each object defining a button with the following properties: `name` (the text to display on the button), `icon` (the tabler icon name or image link to display on the button), `link` (the URL to navigate to when the button is clicked, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row), and `tooltip` (optional text to display when hovering over the button).', 'JSON', TRUE, TRUE),
813816
-- row level
814817
('_sqlpage_css_class', 'For advanced users. Sets a css class on the table row. Added in v0.8.0.', 'TEXT', FALSE, TRUE),
815818
('_sqlpage_color', 'Sets the background color of the row. Added in v0.8.0.', 'COLOR', FALSE, TRUE),
816819
('_sqlpage_footer', 'Sets this row as the table footer. It is recommended that this parameter is applied to the last row. Added in v0.34.0.', 'BOOLEAN', FALSE, TRUE),
817-
('_sqlpage_id', 'Sets the id of the html tabler row element. Allows you to make links targeting a specific row in a table.', 'TEXT', FALSE, TRUE)
820+
('_sqlpage_id', 'Sets the id of the html tabler row element. Allows you to make links targeting a specific row in a table.', 'TEXT', FALSE, TRUE),
821+
('_sqlpage_actions', 'Sets custom action buttons for this specific row in addition to any defined at the table level, The value of this property should be a JSON array of objects, each object defining a button with the following properties: `name` (the text to display on the button), `icon` (the tabler icon name or image link to display on the button), `link` (the URL to navigate to when the button is clicked, possibly containing the `{id}` placeholder that will be replaced by the value of the `_sqlpage_id` property for that row), and `tooltip` (optional text to display when hovering over the button).', 'JSON', FALSE, TRUE)
818822
) x;
819823

820824
INSERT INTO example(component, description, properties) VALUES
@@ -994,9 +998,171 @@ GROUP BY
994998
This will generate a table with the stores in the first column, and the items in the following columns, with the quantity sold in each store for each item.
995999
9961000
', NULL
1001+
),
1002+
(
1003+
'table',
1004+
'# Using row based custom actions in a table
1005+
1006+
The table has a column of buttons, each button defined by the `_sqlpage_actions` column at the table level, and by the `_sqlpage_actions` property at the row level.
1007+
1008+
```sql
1009+
SELECT
1010+
name, vendor, product_number, facility_name,
1011+
lot_number, status, date_of_expiration,
1012+
--Use the unique identifier of the row as the _sqlpage_id property
1013+
standard_id AS _sqlpage_id,
1014+
--Build an array of objects, each object defining a button with the following properties: name, icon, link, tooltip
1015+
json_array(--SQLite specific, refer to your database documentation for the equivalent JSON functions
1016+
--The {id} placeholder in the link property will be replaced by the value of the _sqlpage_id property for that row.
1017+
json_object(''name'', ''history'', ''tooltip'', ''View Standard History'', ''link'', ''./history.sql?standard_id={id}'', ''icon'', ''history''),
1018+
json_object(''name'', ''view_coa'', ''tooltip'', ''View Certificate of Analysis'', ''link'', c_of_a_path, ''icon'', ''file-type-pdf''),
1019+
json_object(''name'', ''edit'', ''tooltip'', ''Edit Standard'', ''link'', ''./update.sql?id={id}'', ''icon'', ''pencil''),
1020+
--We want different actions based on the status of the standard, so we use a CASE statement to build the appropriate action
1021+
CASE
1022+
WHEN status = ''Available'' THEN json_object(
1023+
''name'',''Action'',
1024+
''tooltip'',''Set In Use'',
1025+
''link'',''./actions/set_in_use.sql?standard_id='' || standard_id,
1026+
''icon'',''caret-right''
1027+
)
1028+
WHEN status = ''In Use'' THEN json_object(
1029+
''name'',''Action'',
1030+
''tooltip'',''Retire Standard'',
1031+
''link'',''./actions/retire.sql?standard_id='' || standard_id,
1032+
''icon'',''test-pipe-off''
1033+
)
1034+
WHEN status = ''Retired'' THEN json_object(
1035+
''name'',''Action'',
1036+
''tooltip'',''Discard Standard'',
1037+
''link'',''./actions/discard.sql?standard_id='' || standard_id,
1038+
''icon'',''flask-off''
1039+
)
1040+
-- Include an action with no link or icon as a placeholder to keep the buttons aligned and make sure the header is correct.
1041+
WHEN status = ''Discarded'' THEN json_object(''name'',''Action'')
1042+
1043+
ELSE json_object(''name'',''Action'')
1044+
END
1045+
)
1046+
AS _sqlpage_actions
1047+
FROM standard;
1048+
1049+
```
1050+
1051+
1052+
'
1053+
,
1054+
json('[
1055+
{
1056+
"component": "table"
1057+
},
1058+
{
1059+
"name": "CalStd",
1060+
"vendor": "PharmaCo",
1061+
"product_number": "P1234",
1062+
"facility_name": "A Plant",
1063+
"lot_number": "T23523",
1064+
"status": "Available",
1065+
"date_of_expiration": "2026-10-13",
1066+
"_sqlpage_id": 32,
1067+
"_sqlpage_actions": [
1068+
{
1069+
"name": "history",
1070+
"tooltip": "View Standard History",
1071+
"link": "./history.sql?standard_id={id}",
1072+
"icon": "history"
1073+
},
1074+
{
1075+
"name": "view_coa",
1076+
"tooltip": "View Certificate of Analysis",
1077+
"link": "/c_of_a\\2025-09-30_22h01m21s_B69baKoz.pdf",
1078+
"icon": "file-type-pdf"
1079+
},
1080+
{
1081+
"name": "edit",
1082+
"tooltip": "Edit Standard",
1083+
"link": "./update.sql?id={id}",
1084+
"icon": "pencil"
1085+
},
1086+
{
1087+
"name": "Action",
1088+
"tooltip": "Set In Use",
1089+
"link": "./actions/set_in_use.sql?standard_id=32",
1090+
"icon": "caret-right"
1091+
}
1092+
]
1093+
},
1094+
{
1095+
"name": "CalStd",
1096+
"vendor": "PharmaCo",
1097+
"product_number": "P1234",
1098+
"facility_name": "A Plant",
1099+
"lot_number": "T2352",
1100+
"status": "In Use",
1101+
"date_of_expiration": "2026-10-14",
1102+
"_sqlpage_id": 33,
1103+
"_sqlpage_actions": [
1104+
{
1105+
"name": "history",
1106+
"tooltip": "View Standard History",
1107+
"link": "./history.sql?standard_id={id}",
1108+
"icon": "history"
1109+
},
1110+
{
1111+
"name": "view_coa",
1112+
"tooltip": "View Certificate of Analysis",
1113+
"link": "/c_of_a\\2025-09-30_22h05m13s_cP7gqMyi.pdf",
1114+
"icon": "file-type-pdf"
1115+
},
1116+
{
1117+
"name": "edit",
1118+
"tooltip": "Edit Standard",
1119+
"link": "./update.sql?id={id}",
1120+
"icon": "pencil"
1121+
},
1122+
{
1123+
"name": "Action",
1124+
"tooltip": "Retire Standard",
1125+
"link": "./actions/retire.sql?standard_id=33",
1126+
"icon": "test-pipe-off"
1127+
}
1128+
]
1129+
},
1130+
{
1131+
"name": "CalStd",
1132+
"vendor": "PharmaCo",
1133+
"product_number": "P1234",
1134+
"facility_name": "A Plant",
1135+
"lot_number": "A123",
1136+
"status": "Discarded",
1137+
"date_of_expiration": "2026-09-30",
1138+
"_sqlpage_id": 31,
1139+
"_sqlpage_actions": [
1140+
{
1141+
"name": "history",
1142+
"tooltip": "View Standard History",
1143+
"link": "./history.sql?standard_id={id}",
1144+
"icon": "history"
1145+
},
1146+
{
1147+
"name": "view_coa",
1148+
"tooltip": "View Certificate of Analysis",
1149+
"link": "#",
1150+
"icon": "file-type-pdf"
1151+
},
1152+
{
1153+
"name": "edit",
1154+
"tooltip": "Edit Standard",
1155+
"link": "./update.sql?id={id}",
1156+
"icon": "pencil"
1157+
},
1158+
null
1159+
]
1160+
}
1161+
]')
9971162
);
9981163

9991164

1165+
10001166
INSERT INTO component(name, icon, description) VALUES
10011167
('csv', 'download', 'Lets the user download data as a CSV file.
10021168
Each column from the items in the component will map to a column in the resulting CSV.

sqlpage/templates/table.handlebars

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
{{#if (or search initial_search_value)}}
44
<div class="p-3">
55
<input
6+
id="{{component_index}}-search"
67
type="search"
78
class="form-control form-control-rounded fs-6 search"
89
placeholder="{{default search_placeholder 'Search…'}}"
@@ -52,6 +53,18 @@
5253
</th>
5354
{{/if}}
5455
{{/each}}
56+
{{#if ../edit_url}}<th class="_col_edit">Edit</th>{{/if}}
57+
{{#if ../delete_url}}<th class="_col_delete">Delete</th>{{/if}}
58+
{{#if ../custom_actions}}
59+
{{#each ../custom_actions}}
60+
<th class="_col_custom">{{this.name}}</th>
61+
{{/each}}
62+
{{/if}}
63+
{{#if _sqlpage_actions}}
64+
{{#each _sqlpage_actions}}
65+
<th class="_col_action">{{this.name}}</th>
66+
{{/each}}
67+
{{/if}}
5568
</tr>
5669
</thead>
5770
<tbody class="table-tbody list">{{#delay}}</tbody>{{/delay}}
@@ -78,6 +91,38 @@
7891
</td>
7992
{{/if~}}
8093
{{~/each~}}
94+
{{#if ../edit_url}}
95+
<td class="col-auto fs-2">
96+
<a href="{{replace ../edit_url '{id}' _sqlpage_id}}" class="align-middle link-secondary _col_edit" data-action="edit" title="Edit">
97+
{{~icon_img 'edit'~}}
98+
</a>
99+
</td>
100+
{{/if}}
101+
{{#if ../delete_url}}
102+
<td class="col-auto fs-2">
103+
<a href="{{replace ../delete_url '{id}' _sqlpage_id}}" class="align-middle link-secondary _col_delete" data-action="delete" title="Delete">
104+
{{~icon_img 'trash'~}}
105+
</a>
106+
</td>
107+
{{/if}}
108+
{{#if ../custom_actions}}
109+
{{#each ../custom_actions}}
110+
<td class="col-auto fs-2">
111+
<a href="{{replace this.link '{id}' ../_sqlpage_id}}" class="align-middle link-secondary" data-action="{{this.name}}" title="{{default this.tooltip this.name}}">{{!Title property sets the tooltip text}}
112+
{{~icon_img this.icon~}}
113+
</a>
114+
</td>
115+
{{/each}}
116+
{{/if}}
117+
{{#if _sqlpage_actions}}
118+
{{#each _sqlpage_actions}}
119+
<td class="col-auto fs-2">
120+
<a href="{{replace this.link '{id}' ../_sqlpage_id}}" class="align-middle link-secondary" data-action="{{this.name}}" title="{{default this.tooltip this.name}}">
121+
{{~icon_img this.icon~}}
122+
</a>
123+
</td>
124+
{{/each}}
125+
{{/if}}
81126
</tr>
82127
{{!~
83128
After this <tr> has been rendered, if this was a footer, we need to reopen a new <tbody>

0 commit comments

Comments
 (0)