pgkiln 0.53.0 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SECURITY.md +1 -0
- package/docs/apex-feature-parity.md +5 -5
- package/docs/guide/03-builder.md +40 -7
- package/docs/guide/12-development.md +9 -3
- package/examples/gallery/README.md +37 -6
- package/examples/gallery/gallery.json +23 -1
- package/examples/gallery/samples/sample-calendar.sql +172 -0
- package/examples/gallery/samples/sample-cards.sql +157 -0
- package/examples/gallery/samples/sample-charts.sql +265 -0
- package/examples/gallery/samples/sample-dynamic-actions.sql +177 -0
- package/examples/gallery/samples/sample-grids.sql +151 -0
- package/examples/gallery/samples/sample-reporting.sql +151 -0
- package/examples/gallery/samples/ux-patterns.sql +295 -0
- package/examples/gallery/utilities/announcements.json +24 -0
- package/examples/gallery/utilities/lookup-lists.json +28 -0
- package/examples/gallery/utilities/release-notes.json +41 -0
- package/package.json +1 -1
- package/public/app.css +2 -0
- package/public/builder.css +21 -1
- package/src/builder/gallery.ts +94 -47
- package/src/runtime/charts.ts +4 -1
- package/src/runtime/regions.ts +8 -5
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
-- =====================================================================
|
|
2
|
+
-- Sample app "Sample Interactive Grids" (App Gallery → Sample Apps)
|
|
3
|
+
--
|
|
4
|
+
-- The interactive grid: an editable grid made by the wizard; a grid with
|
|
5
|
+
-- select lists, required columns, totals, a frozen column, a row menu and a
|
|
6
|
+
-- default column layout; a master grid with its detail grid; and a
|
|
7
|
+
-- read-only grid with its single row, group by and chart views.
|
|
8
|
+
--
|
|
9
|
+
-- Installed by an administrator from the App Gallery, or with
|
|
10
|
+
-- psql "$DATABASE_URL" -1 -f examples/gallery/samples/sample-grids.sql
|
|
11
|
+
-- then open /a/sample-grids and sign in as demo / demo.
|
|
12
|
+
-- =====================================================================
|
|
13
|
+
|
|
14
|
+
create or replace function pg_temp.page_id(p_alias text, p_page int) returns int language sql stable as
|
|
15
|
+
$$ select p.id from meta.page p join meta.app a on a.id = p.app_id where a.alias = p_alias and p.page_no = p_page $$;
|
|
16
|
+
|
|
17
|
+
-- 1. Schema and data ---------------------------------------------------------
|
|
18
|
+
create schema sample_grids;
|
|
19
|
+
|
|
20
|
+
create table sample_grids.team (
|
|
21
|
+
id int generated always as identity primary key,
|
|
22
|
+
name text not null unique,
|
|
23
|
+
location text,
|
|
24
|
+
budget numeric(12, 2)
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
create table sample_grids.member (
|
|
28
|
+
id int generated always as identity primary key,
|
|
29
|
+
team_id int not null references sample_grids.team,
|
|
30
|
+
name text not null,
|
|
31
|
+
role text not null default 'Developer' check (role in ('Lead', 'Developer', 'Designer', 'Tester', 'Analyst')),
|
|
32
|
+
starts date not null default current_date,
|
|
33
|
+
hours int not null default 40 check (hours between 0 and 60),
|
|
34
|
+
rate numeric(8, 2),
|
|
35
|
+
remote boolean not null default false
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
insert into sample_grids.team (name, location, budget) values
|
|
39
|
+
('Platform', 'Amsterdam', 480000), ('Mobile', 'Rotterdam', 310000), ('Data', 'Utrecht', 260000), ('Design', 'Amsterdam', 150000);
|
|
40
|
+
|
|
41
|
+
insert into sample_grids.member (team_id, name, role, starts, hours, rate, remote) values
|
|
42
|
+
(1, 'Ada', 'Lead', '2019-03-01', 40, 95, false), (1, 'Linus', 'Developer', '2021-06-14', 40, 80, true),
|
|
43
|
+
(1, 'Grace', 'Developer', '2022-01-10', 32, 82, false), (1, 'Ken', 'Tester', '2023-09-01', 24, 65, true),
|
|
44
|
+
(2, 'Margaret', 'Lead', '2020-02-03', 40, 92, false), (2, 'Dennis', 'Developer', '2021-11-22', 36, 78, false),
|
|
45
|
+
(2, 'Barbara', 'Designer', '2024-04-15', 20, 70, true), (3, 'Edgar', 'Analyst', '2018-08-20', 40, 88, false),
|
|
46
|
+
(3, 'Michael', 'Developer', '2022-05-30', 40, 79, true), (3, 'Frances', 'Analyst', '2025-01-06', 28, 72, false),
|
|
47
|
+
(4, 'Susan', 'Designer', '2019-10-01', 40, 85, false), (4, 'Jef', 'Designer', '2023-03-13', 32, 74, true);
|
|
48
|
+
|
|
49
|
+
-- 2. The application's database role ----------------------------------------
|
|
50
|
+
do $$ begin
|
|
51
|
+
if not exists (select 1 from pg_roles where rolname = 'app_sample_grids') then create role app_sample_grids nologin; end if;
|
|
52
|
+
end $$;
|
|
53
|
+
grant app_sample_grids to pgkiln_runtime;
|
|
54
|
+
grant usage on schema sample_grids to app_sample_grids;
|
|
55
|
+
grant select, insert, update, delete on all tables in schema sample_grids to app_sample_grids;
|
|
56
|
+
|
|
57
|
+
-- 3. The application ----------------------------------------------------------
|
|
58
|
+
insert into meta.app (alias, name, home_page, authentication, db_role)
|
|
59
|
+
values ('sample-grids', 'Sample Interactive Grids', 1, 'app_users', 'app_sample_grids');
|
|
60
|
+
|
|
61
|
+
insert into meta.app_user (app_id, username, password_hash, roles)
|
|
62
|
+
select id, 'demo', meta.hash_password('demo'), '{}' from meta.app where alias = 'sample-grids';
|
|
63
|
+
|
|
64
|
+
insert into meta.page (app_id, page_no, name, title, parent_page)
|
|
65
|
+
select a.id, p.no, p.name, p.name, p.parent
|
|
66
|
+
from meta.app a, (values (1, 'Sample Interactive Grids', null), (3, 'Grid features', 1), (5, 'Reading and analysing', 1)) as p (no, name, parent)
|
|
67
|
+
where a.alias = 'sample-grids';
|
|
68
|
+
|
|
69
|
+
-- page 2: an editable grid on the teams, as the Interactive grid wizard makes it
|
|
70
|
+
select meta.generate_page('sample-grids', 'grid', 'sample_grids.team', 2, '{"label": "Teams", "nav": false}');
|
|
71
|
+
-- page 4: master-detail, teams and their members (the Master-detail wizard)
|
|
72
|
+
select meta.generate_page('sample-grids', 'master_detail', 'sample_grids.team', 4, '{"label": "Teams and members", "nav": false}');
|
|
73
|
+
update meta.page set parent_page = 1 where app_id = (select id from meta.app where alias = 'sample-grids') and page_no in (2, 4);
|
|
74
|
+
|
|
75
|
+
insert into meta.nav_entry (app_id, seq, label, icon, target_page)
|
|
76
|
+
select a.id, n.seq, n.label, n.icon, n.page
|
|
77
|
+
from meta.app a, (values
|
|
78
|
+
(10, 'Home', 'home', 1), (20, 'Teams', 'grid', 2), (30, 'Grid features', 'sliders', 3),
|
|
79
|
+
(40, 'Teams and members', 'users', 4), (50, 'Reading and analysing', 'chart', 5)
|
|
80
|
+
) as n (seq, label, icon, page)
|
|
81
|
+
where a.alias = 'sample-grids';
|
|
82
|
+
|
|
83
|
+
insert into meta.list (app_id, name, type, description)
|
|
84
|
+
select id, 'GRID_TOPICS', 'static', 'The pages of Sample Interactive Grids' from meta.app where alias = 'sample-grids';
|
|
85
|
+
|
|
86
|
+
insert into meta.list_entry (app_id, list_name, seq, label, icon, target_page, description)
|
|
87
|
+
select a.id, 'GRID_TOPICS', e.seq, e.label, e.icon, e.page, e.description
|
|
88
|
+
from meta.app a, (values
|
|
89
|
+
(10, 'Teams', 'grid', 2, 'An editable grid as the wizard makes it: edit cells, add rows, delete rows, Save.'),
|
|
90
|
+
(20, 'Grid features', 'sliders', 3, 'Select lists, required columns, totals, a frozen column, a row menu and a column layout.'),
|
|
91
|
+
(30, 'Teams and members', 'users', 4, 'Master-detail: choose a team, edit its members below.'),
|
|
92
|
+
(40, 'Reading and analysing', 'chart', 5, 'A read-only grid with the single row, group by and chart views.')
|
|
93
|
+
) as e (seq, label, icon, page, description)
|
|
94
|
+
where a.alias = 'sample-grids';
|
|
95
|
+
|
|
96
|
+
insert into meta.region (page_id, seq, title, type, columns, template, source, table_name, pk_column, config, static_id)
|
|
97
|
+
select pg_temp.page_id('sample-grids', r.page), r.seq, r.title, r.type, 12, r.template, r.source, r.tab, r.pk, r.config::jsonb, r.sid
|
|
98
|
+
from (values
|
|
99
|
+
-- 1 Home
|
|
100
|
+
(1, 10, 'Sample Interactive Grids', 'static', 'hero',
|
|
101
|
+
'<p>An interactive grid edits the rows of one table in place: click a cell (or press Enter or F2) to edit it, the arrow keys move between cells, Ctrl+C and Ctrl+V copy and paste ranges from and to a spreadsheet. Only changed cells are saved, and when one row fails nothing is saved. Without a <code>grid_dml</code> process a grid is read-only.</p>',
|
|
102
|
+
null, null, '{"icon": "grid"}', null),
|
|
103
|
+
(1, 20, 'Topics', 'list', 'plain', null, null, null, '{"list": "GRID_TOPICS", "template": "cards"}', null),
|
|
104
|
+
|
|
105
|
+
-- 2 Teams (the wizard's grid follows at seq 10)
|
|
106
|
+
(2, 5, 'About this page', 'static', 'plain',
|
|
107
|
+
'<p class="lead">The wizard made this grid: a region of type <code>grid</code> on <code>sample_grids.team</code> with its key column, and a <code>grid_dml</code> process that saves it. Try <strong>Add row</strong>, change a budget and press <strong>Save</strong>; a duplicate name is refused by the table''s unique constraint, with the row number.</p>',
|
|
108
|
+
null, null, '{}', null),
|
|
109
|
+
|
|
110
|
+
-- 3 Grid features
|
|
111
|
+
(3, 5, 'About this page', 'static', 'plain',
|
|
112
|
+
'<p class="lead">The grid''s attributes: <code>columns</code> gives the team column a list of values and makes the name required; <code>aggregates</code> adds totals over every row of the search; <code>frozen</code> keeps the name in view while the grid scrolls sideways; <code>row_actions</code> adds a menu per row (duplicate, delete); <code>layout</code> sets the default order and widths, and every user can rearrange it (Actions → Columns).</p>',
|
|
113
|
+
null, null, '{}', null),
|
|
114
|
+
(3, 10, 'Members', 'grid', 'standard',
|
|
115
|
+
E'select id, name, team_id, role, starts, hours, rate, remote\n from sample_grids.member order by team_id, name',
|
|
116
|
+
'sample_grids.member', 'id',
|
|
117
|
+
'{"page_size": 10,
|
|
118
|
+
"headings": {"team_id": "Team", "starts": "Started", "hours": "Hours a week", "rate": "Hourly rate"},
|
|
119
|
+
"columns": {"name": {"required": true},
|
|
120
|
+
"team_id": {"lov": "select name, id from sample_grids.team order by name", "required": true},
|
|
121
|
+
"role": {"lov": "STATIC:Lead,Developer,Designer,Tester,Analyst", "required": true}},
|
|
122
|
+
"formats": {"rate": "999G990D00"},
|
|
123
|
+
"aggregates": {"hours": ["sum", "avg"], "rate": "avg", "id": "count"},
|
|
124
|
+
"frozen": 1,
|
|
125
|
+
"hidden": ["id"],
|
|
126
|
+
"row_actions": {"duplicate": true, "delete": true},
|
|
127
|
+
"layout": {"order": ["name", "team_id", "role", "hours", "rate", "starts", "remote"], "widths": {"name": 160}}}', 'members'),
|
|
128
|
+
|
|
129
|
+
-- 4 Teams and members (the wizard's grids follow at seq 10 and 20)
|
|
130
|
+
(4, 5, 'About this page', 'static', 'plain',
|
|
131
|
+
'<p class="lead">The master-detail wizard made this page. The teams grid has <code>select_row</code>: choosing a row puts its key in the hidden item <code>P4_ID</code>. The members grid has <code>master</code>: its query uses <code>:P4_ID</code>, it refreshes in place when another team is chosen, and its new rows get that team.</p>',
|
|
132
|
+
null, null, '{}', null),
|
|
133
|
+
|
|
134
|
+
-- 5 Reading and analysing
|
|
135
|
+
(5, 5, 'About this page', 'static', 'plain',
|
|
136
|
+
'<p class="lead">This grid has no <code>grid_dml</code> process and <code>allow</code> switches off insert, update and delete, so it only reads. Its <strong>views</strong> are still there: open a row in the <em>Single row view</em> (the row menu or Actions), or set up a <em>Group by</em> or a <em>Chart</em> under Actions, for example the hours per team.</p>',
|
|
137
|
+
null, null, '{}', null),
|
|
138
|
+
(5, 10, 'Members per team', 'grid', 'standard',
|
|
139
|
+
E'select m.id, m.name, t.name as team, m.role, m.hours, m.rate, m.remote\n from sample_grids.member m join sample_grids.team t on t.id = m.team_id\n order by t.name, m.name',
|
|
140
|
+
'sample_grids.member', 'id',
|
|
141
|
+
'{"page_size": 25, "allow": {"insert": false, "update": false, "delete": false}, "views": ["row", "group", "chart"],
|
|
142
|
+
"hidden": ["id"], "aggregates": {"hours": "sum"}, "row_actions": {}}', 'analysis')
|
|
143
|
+
) as r (page, seq, title, type, template, source, tab, pk, config, sid);
|
|
144
|
+
|
|
145
|
+
insert into meta.process (page_id, seq, name, type, region_id)
|
|
146
|
+
select pg_temp.page_id('sample-grids', 3), 10, 'Save the members', 'grid_dml', r.id
|
|
147
|
+
from meta.region r where r.page_id = pg_temp.page_id('sample-grids', 3) and r.static_id = 'members';
|
|
148
|
+
|
|
149
|
+
-- the detail grid of page 4: the role as a select list
|
|
150
|
+
update meta.region set config = jsonb_set(config, '{columns,role}', '{"lov": "STATIC:Lead,Developer,Designer,Tester,Analyst", "required": true}')
|
|
151
|
+
where page_id = pg_temp.page_id('sample-grids', 4) and seq = 20;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
-- =====================================================================
|
|
2
|
+
-- Sample app "Sample Reporting" (App Gallery → Sample Apps)
|
|
3
|
+
--
|
|
4
|
+
-- Reports and the ways to search them: an interactive report with its form,
|
|
5
|
+
-- a faceted search, smart filters, and a classic report with column
|
|
6
|
+
-- display options, a column template and a link.
|
|
7
|
+
--
|
|
8
|
+
-- Installed by an administrator from the App Gallery, or with
|
|
9
|
+
-- psql "$DATABASE_URL" -1 -f examples/gallery/samples/sample-reporting.sql
|
|
10
|
+
-- then open /a/sample-reporting and sign in as demo / demo.
|
|
11
|
+
-- =====================================================================
|
|
12
|
+
|
|
13
|
+
create or replace function pg_temp.page_id(p_alias text, p_page int) returns int language sql stable as
|
|
14
|
+
$$ select p.id from meta.page p join meta.app a on a.id = p.app_id where a.alias = p_alias and p.page_no = p_page $$;
|
|
15
|
+
create or replace function pg_temp.region_id(p_alias text, p_page int, p_static text) returns int language sql stable as
|
|
16
|
+
$$ select r.id from meta.region r where r.page_id = pg_temp.page_id(p_alias, p_page) and r.static_id = p_static $$;
|
|
17
|
+
|
|
18
|
+
-- 1. Schema and data ---------------------------------------------------------
|
|
19
|
+
create schema sample_reporting;
|
|
20
|
+
|
|
21
|
+
create table sample_reporting.book (
|
|
22
|
+
id int generated always as identity primary key,
|
|
23
|
+
title text not null,
|
|
24
|
+
author text not null,
|
|
25
|
+
genre text not null check (genre in ('Novel', 'Crime', 'Science fiction', 'History', 'Science', 'Poetry')),
|
|
26
|
+
language text not null default 'English',
|
|
27
|
+
published int not null check (published between 1500 and 2100),
|
|
28
|
+
pages int,
|
|
29
|
+
rating int check (rating between 1 and 5),
|
|
30
|
+
price numeric(8, 2),
|
|
31
|
+
in_stock boolean not null default true
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
insert into sample_reporting.book (title, author, genre, language, published, pages, rating, price, in_stock) values
|
|
35
|
+
('Pride and Prejudice', 'Jane Austen', 'Novel', 'English', 1813, 432, 5, 9.99, true),
|
|
36
|
+
('Middlemarch', 'George Eliot', 'Novel', 'English', 1871, 880, 4, 12.50, true),
|
|
37
|
+
('Max Havelaar', 'Multatuli', 'Novel', 'Dutch', 1860, 352, 4, 11.00, false),
|
|
38
|
+
('The Hound of the Baskervilles', 'Arthur Conan Doyle', 'Crime', 'English', 1902, 256, 4, 7.95, true),
|
|
39
|
+
('Murder on the Orient Express', 'Agatha Christie', 'Crime', 'English', 1934, 274, 5, 8.99, true),
|
|
40
|
+
('Maigret and the Yellow Dog', 'Georges Simenon', 'Crime', 'French', 1931, 160, 3, 9.50, true),
|
|
41
|
+
('The Time Machine', 'H. G. Wells', 'Science fiction', 'English', 1895, 118, 4, 6.50, true),
|
|
42
|
+
('Foundation', 'Isaac Asimov', 'Science fiction', 'English', 1951, 255, 5, 10.99, false),
|
|
43
|
+
('Solaris', 'Stanisław Lem', 'Science fiction', 'Polish', 1961, 204, 4, 11.95, true),
|
|
44
|
+
('The Guns of August', 'Barbara Tuchman', 'History', 'English', 1962, 640, 5, 15.00, true),
|
|
45
|
+
('Homo Ludens', 'Johan Huizinga', 'History', 'Dutch', 1938, 288, 3, 13.50, true),
|
|
46
|
+
('The Waning of the Middle Ages', 'Johan Huizinga', 'History', 'Dutch', 1919, 400, 4, 14.00, false),
|
|
47
|
+
('On the Origin of Species', 'Charles Darwin', 'Science', 'English', 1859, 502, 5, 10.00, true),
|
|
48
|
+
('A Brief History of Time', 'Stephen Hawking', 'Science', 'English', 1988, 212, 4, 12.99, true),
|
|
49
|
+
('The Double Helix', 'James Watson', 'Science', 'English', 1968, 226, 3, 11.50, true),
|
|
50
|
+
('Leaves of Grass', 'Walt Whitman', 'Poetry', 'English', 1855, 384, 4, 9.00, true),
|
|
51
|
+
('Les Fleurs du mal', 'Charles Baudelaire', 'Poetry', 'French', 1857, 300, 5, 8.50, false),
|
|
52
|
+
('Verzamelde gedichten', 'Lucebert', 'Poetry', 'Dutch', 1974, 620, 3, 29.95, true);
|
|
53
|
+
|
|
54
|
+
-- 2. The application's database role ----------------------------------------
|
|
55
|
+
do $$ begin
|
|
56
|
+
if not exists (select 1 from pg_roles where rolname = 'app_sample_reporting') then create role app_sample_reporting nologin; end if;
|
|
57
|
+
end $$;
|
|
58
|
+
grant app_sample_reporting to pgkiln_runtime;
|
|
59
|
+
grant usage on schema sample_reporting to app_sample_reporting;
|
|
60
|
+
grant select, insert, update, delete on all tables in schema sample_reporting to app_sample_reporting;
|
|
61
|
+
|
|
62
|
+
-- 3. The application ----------------------------------------------------------
|
|
63
|
+
insert into meta.app (alias, name, home_page, authentication, db_role)
|
|
64
|
+
values ('sample-reporting', 'Sample Reporting', 1, 'app_users', 'app_sample_reporting');
|
|
65
|
+
|
|
66
|
+
insert into meta.app_user (app_id, username, password_hash, roles)
|
|
67
|
+
select id, 'demo', meta.hash_password('demo'), '{}' from meta.app where alias = 'sample-reporting';
|
|
68
|
+
|
|
69
|
+
insert into meta.page (app_id, page_no, name, title, parent_page)
|
|
70
|
+
select a.id, p.no, p.name, p.name, p.parent
|
|
71
|
+
from meta.app a, (values (1, 'Sample Reporting', null), (5, 'Smart filters', 1), (6, 'Classic report', 1)) as p (no, name, parent)
|
|
72
|
+
where a.alias = 'sample-reporting';
|
|
73
|
+
|
|
74
|
+
-- page 2 and its form, page 3: the Report and form wizard; page 4: the Faceted search wizard
|
|
75
|
+
select meta.generate_page('sample-reporting', 'report_form', 'sample_reporting.book', 2, '{"label": "Books", "form_page": 3, "nav": false}');
|
|
76
|
+
select meta.generate_page('sample-reporting', 'facets', 'sample_reporting.book', 4,
|
|
77
|
+
'{"label": "Faceted search", "nav": false, "facets": ["genre", "language", "rating", "in_stock", "published"]}');
|
|
78
|
+
update meta.page set parent_page = 1 where app_id = (select id from meta.app where alias = 'sample-reporting') and page_no in (2, 4);
|
|
79
|
+
update meta.item set type = 'select', lov = 'STATIC:Novel,Crime,Science fiction,History,Science,Poetry'
|
|
80
|
+
where page_id = pg_temp.page_id('sample-reporting', 3) and name = 'P3_GENRE';
|
|
81
|
+
update meta.item set type = 'rating' where page_id = pg_temp.page_id('sample-reporting', 3) and name = 'P3_RATING';
|
|
82
|
+
|
|
83
|
+
insert into meta.nav_entry (app_id, seq, label, icon, target_page)
|
|
84
|
+
select a.id, n.seq, n.label, n.icon, n.page
|
|
85
|
+
from meta.app a, (values
|
|
86
|
+
(10, 'Home', 'home', 1), (20, 'Interactive report', 'table', 2), (30, 'Faceted search', 'filter', 4),
|
|
87
|
+
(40, 'Smart filters', 'search', 5), (50, 'Classic report', 'list', 6)
|
|
88
|
+
) as n (seq, label, icon, page)
|
|
89
|
+
where a.alias = 'sample-reporting';
|
|
90
|
+
|
|
91
|
+
insert into meta.list (app_id, name, type, description)
|
|
92
|
+
select id, 'REPORT_TOPICS', 'static', 'The pages of Sample Reporting' from meta.app where alias = 'sample-reporting';
|
|
93
|
+
|
|
94
|
+
insert into meta.list_entry (app_id, list_name, seq, label, icon, target_page, description)
|
|
95
|
+
select a.id, 'REPORT_TOPICS', e.seq, e.label, e.icon, e.page, e.description
|
|
96
|
+
from meta.app a, (values
|
|
97
|
+
(10, 'Interactive report', 'table', 2, 'Search, filters, sorting, control breaks, aggregates, highlights, charts, saved reports and downloads.'),
|
|
98
|
+
(20, 'Faceted search', 'filter', 4, 'Filters with counts beside the report, made by the Faceted search wizard.'),
|
|
99
|
+
(30, 'Smart filters', 'search', 5, 'One search field with filter chips and suggestions.'),
|
|
100
|
+
(40, 'Classic report', 'list', 6, 'A report without the search and Actions menu, with column display options and a column template.')
|
|
101
|
+
) as e (seq, label, icon, page, description)
|
|
102
|
+
where a.alias = 'sample-reporting';
|
|
103
|
+
|
|
104
|
+
insert into meta.region (page_id, seq, title, type, columns, template, source, config, static_id)
|
|
105
|
+
select pg_temp.page_id('sample-reporting', r.page), r.seq, r.title, r.type, r.cols, r.template, r.source, r.config::jsonb, r.sid
|
|
106
|
+
from (values
|
|
107
|
+
-- 1 Home
|
|
108
|
+
(1, 10, 'Sample Reporting', 'static', 12, 'hero',
|
|
109
|
+
'<p>A report region shows the rows of any SELECT. As an <em>interactive report</em> the users search, filter, sort, group, chart, save and download it themselves; everything they enter becomes literals, columns are checked against the query, and the state lives in the URL, so a report can be bookmarked.</p>',
|
|
110
|
+
'{"icon": "table"}', null),
|
|
111
|
+
(1, 20, 'Topics', 'list', 12, 'plain', null, '{"list": "REPORT_TOPICS", "template": "cards"}', null),
|
|
112
|
+
|
|
113
|
+
-- 2 Interactive report (the wizard's report follows at seq 10)
|
|
114
|
+
(2, 5, 'About this page', 'static', 12, 'plain',
|
|
115
|
+
'<p class="lead">The Report and form wizard made this page: an interactive report with a link to a modal form. Click a column heading for its menu (sort, hide, control break, its values), or open <em>Actions</em> for filters, aggregates, highlights, computed columns, group by, pivot, a chart, saved reports and downloads (CSV, Excel, PDF).</p>',
|
|
116
|
+
'{}', null),
|
|
117
|
+
|
|
118
|
+
-- 4 Faceted search (the wizard's regions follow)
|
|
119
|
+
(4, 5, 'About this page', 'static', 12, 'plain',
|
|
120
|
+
'<p class="lead">The Faceted search wizard made this page: a <code>facets</code> region in the left column that filters the report beside it. Each value shows how many rows it would leave, counting the search and the other facets.</p>',
|
|
121
|
+
'{}', null),
|
|
122
|
+
|
|
123
|
+
-- 5 Smart filters
|
|
124
|
+
(5, 5, 'About this page', 'static', 12, 'plain',
|
|
125
|
+
'<p class="lead">A <code>smart_filters</code> region is the compact alternative: one search field above the report, the filters in use as chips and suggestions below it. Type <em>dutch</em> or <em>crime</em> and choose a suggestion.</p>',
|
|
126
|
+
'{}', null),
|
|
127
|
+
(5, 10, 'Search', 'smart_filters', 12, 'plain', null, '{}', 'smart'),
|
|
128
|
+
(5, 20, 'Books', 'report', 12, 'standard',
|
|
129
|
+
E'select title, author, genre, language, published, rating, price from sample_reporting.book order by title',
|
|
130
|
+
'{"formats": {"price": "999G990D00"}}', 'smart-report'),
|
|
131
|
+
|
|
132
|
+
-- 6 Classic report
|
|
133
|
+
(6, 5, 'About this page', 'static', 12, 'plain',
|
|
134
|
+
'<p class="lead">With <code>"searchable": false</code> a report is a classic report: no search field and no Actions menu. <code>column_options</code> sets how columns look (bold, muted, monospace, right-aligned), <code>column_templates</code> draws the stock column through the built-in badge component, and <code>link</code> makes the title open the form.</p>',
|
|
135
|
+
'{}', null),
|
|
136
|
+
(6, 10, 'Books per genre', 'report', 12, 'standard',
|
|
137
|
+
E'select id, title, author, genre, published, price,\n case when in_stock then ''In stock'' else ''Sold out'' end as stock,\n case when in_stock then ''success'' else ''danger'' end as stock_state\n from sample_reporting.book order by genre, title',
|
|
138
|
+
'{"searchable": false, "page_size": 50, "hidden": ["id", "stock_state"],
|
|
139
|
+
"link": {"column": "title", "page": 3, "items": {"P3_ID": "#id#"}},
|
|
140
|
+
"formats": {"price": "999G990D00"},
|
|
141
|
+
"column_options": {"title": ["to-col-bold"], "author": ["to-col-muted"], "published": ["to-col-mono"], "price": ["to-col-right"]},
|
|
142
|
+
"column_templates": {"stock": {"component": "ut_badge", "attributes": {"LABEL": "#stock#", "STATE": "#stock_state#"}}}}', null)
|
|
143
|
+
) as r (page, seq, title, type, cols, template, source, config, sid);
|
|
144
|
+
|
|
145
|
+
update meta.region set config = jsonb_build_object(
|
|
146
|
+
'report', pg_temp.region_id('sample-reporting', 5, 'smart-report'),
|
|
147
|
+
'placeholder', 'Search or filter the books…',
|
|
148
|
+
'facets', '[{"column": "genre", "label": "Genre"}, {"column": "language", "label": "Language"},
|
|
149
|
+
{"column": "published", "label": "Published", "type": "range",
|
|
150
|
+
"ranges": [{"to": 1900}, {"from": 1900, "to": 1950}, {"from": 1950}]}]'::jsonb)
|
|
151
|
+
where id = pg_temp.region_id('sample-reporting', 5, 'smart');
|