@saltcorn/history-control 0.4.1 → 0.5.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/common.js CHANGED
@@ -68,6 +68,7 @@ const updateRow = async (table_name, update_in, version_id) => {
68
68
  const sqlParts = [],
69
69
  values = [];
70
70
  const nkeys = Object.keys(update).length;
71
+ if (nkeys === 0) return;
71
72
  const [version, id] = version_id.split("_");
72
73
  Object.entries(update).forEach(([k, v], ix) => {
73
74
  sqlParts.push(`"${db.sqlsanitize(k)}"=$${ix + 1}`);
package/index.js CHANGED
@@ -96,5 +96,5 @@ module.exports = {
96
96
  sc_plugin_api_version: 1,
97
97
  actions: features?.table_undo ? actions : undefined,
98
98
  table_providers: require("./table-provider.js"),
99
- viewtemplates: [require("./diffview")],
99
+ viewtemplates: [require("./diffview"), require("./rowdiffview")],
100
100
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saltcorn/history-control",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Allow users to interact with row history",
5
5
  "main": "index.js",
6
6
  "dependencies": {
package/rowdiffview.js ADDED
@@ -0,0 +1,185 @@
1
+ const Field = require("@saltcorn/data/models/field");
2
+ const Table = require("@saltcorn/data/models/table");
3
+ const Form = require("@saltcorn/data/models/form");
4
+ const User = require("@saltcorn/data/models/user");
5
+ const View = require("@saltcorn/data/models/view");
6
+ const { hashState } = require("@saltcorn/data/utils");
7
+ const Workflow = require("@saltcorn/data/models/workflow");
8
+ const HtmlDiff = require("htmldiff-js");
9
+ const {
10
+ text,
11
+ div,
12
+ h3,
13
+ style,
14
+ a,
15
+ script,
16
+ pre,
17
+ domReady,
18
+ p,
19
+ i,
20
+ select,
21
+ option,
22
+ h2,
23
+ button,
24
+ } = require("@saltcorn/markup/tags");
25
+ const { radio_group, checkbox_group } = require("@saltcorn/markup/helpers");
26
+ const moment = require("moment");
27
+
28
+ const get_state_fields = () => [
29
+ {
30
+ name: "id",
31
+ type: "Integer",
32
+ required: true,
33
+ primary_key: true,
34
+ },
35
+ ];
36
+
37
+ const configuration_workflow = (req) =>
38
+ new Workflow({
39
+ steps: [
40
+ {
41
+ name: "Difference View",
42
+ form: async (context) => {
43
+ const table = await Table.findOne({ id: context.table_id });
44
+ const show_views = await View.find_table_views_where(
45
+ context.table_id,
46
+ ({ state_fields, viewtemplate, viewrow }) =>
47
+ viewtemplate.runMany &&
48
+ viewrow.name !== context.viewname &&
49
+ state_fields.some((sf) => sf.name === "id")
50
+ );
51
+ const show_view_opts = show_views.map((v) => v.select_option);
52
+ return new Form({
53
+ fields: [
54
+ {
55
+ name: "show_view",
56
+ label: req.__("Single item view"),
57
+ type: "String",
58
+ sublabel:
59
+ req.__("The underlying individual view of each table row") +
60
+ ". " +
61
+ a(
62
+ {
63
+ "data-dyn-href": `\`/viewedit/config/\${show_view}\``,
64
+ target: "_blank",
65
+ },
66
+ req.__("Configure")
67
+ ),
68
+ required: true,
69
+ attributes: {
70
+ options: show_view_opts,
71
+ },
72
+ },
73
+ {
74
+ name: "min_interval_secs",
75
+ label: "Minimum interval (s)",
76
+ type: "Integer",
77
+ },
78
+ {
79
+ name: "date_format",
80
+ label: "Date format",
81
+ type: "String",
82
+ sublabel: "moment.js format specifier",
83
+ },
84
+ ],
85
+ });
86
+ },
87
+ },
88
+ ],
89
+ });
90
+
91
+ const run = async (
92
+ table_id,
93
+ viewname,
94
+ { show_view, min_interval_secs, date_format },
95
+ state,
96
+ extraArgs
97
+ ) => {
98
+ const table = await Table.findOne({ id: table_id });
99
+ const stateHash = hashState(state, show_view);
100
+
101
+ const id = state[table.pk_name];
102
+
103
+ if (!id) return `Need id`;
104
+
105
+ let hist = await table.get_history(id);
106
+
107
+ let last = 0;
108
+ let last_changed_by = undefined;
109
+ hist = hist.filter((row) => {
110
+ const myEpoch = Math.round(new Date(row._time).getTime() / 1000);
111
+ if (
112
+ myEpoch - last > min_interval_secs ||
113
+ (row._userid && row._userid !== last_changed_by)
114
+ ) {
115
+ //include
116
+ last = myEpoch;
117
+ last_changed_by = row._userid;
118
+ return true;
119
+ } else return false;
120
+ });
121
+
122
+ if (!hist || !hist.length) return "No versions recorded";
123
+ hist = hist.reverse();
124
+
125
+ const userIds = new Set(hist.map((h) => h._userid));
126
+ const users = await User.find({ id: { in: [...userIds] } });
127
+ const emails = {};
128
+ users.forEach((u) => (emails[u.id] = u.email));
129
+ const view = View.findOne({ name: show_view });
130
+ const rendered = await view.viewtemplateObj.renderRows(
131
+ table,
132
+ view.name,
133
+ view.configuration,
134
+ extraArgs,
135
+ hist,
136
+ state
137
+ );
138
+ return div(
139
+ {
140
+ class: ["accordion"],
141
+ id: `top${stateHash}`,
142
+ },
143
+ rendered.map((html, ix) => {
144
+ const row = hist[ix];
145
+ return div(
146
+ { class: "accordion-item" },
147
+ h2(
148
+ { class: "accordion-header", id: `a${stateHash}head${ix}` },
149
+ button(
150
+ {
151
+ class: ["accordion-button", "collapsed"],
152
+ type: "button",
153
+ "data-bs-toggle": "collapse",
154
+ "data-bs-target": `#a${stateHash}tab${ix}`,
155
+ "aria-expanded": "false",
156
+ "aria-controls": `a${stateHash}tab${ix}`,
157
+ },
158
+ date_format
159
+ ? moment(row._time).format(date_format)
160
+ : row._time.toString(),
161
+ " - ",
162
+ emails[row._userid]
163
+ )
164
+ ),
165
+ div(
166
+ {
167
+ class: ["accordion-collapse", "collapse"],
168
+ id: `a${stateHash}tab${ix}`,
169
+ "aria-labelledby": `a${stateHash}head${ix}`,
170
+ "data-bs-parent": `#top${stateHash}`,
171
+ },
172
+ div({ class: ["accordion-body"] }, html)
173
+ )
174
+ );
175
+ })
176
+ );
177
+ };
178
+
179
+ module.exports = {
180
+ name: "History Row Difference",
181
+ display_state_form: false,
182
+ get_state_fields,
183
+ configuration_workflow,
184
+ run,
185
+ };