@saltcorn/history-control 0.5.0 → 0.5.2

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/rowdiffview.js +75 -17
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saltcorn/history-control",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Allow users to interact with row history",
5
5
  "main": "index.js",
6
6
  "dependencies": {
package/rowdiffview.js CHANGED
@@ -23,6 +23,7 @@ const {
23
23
  button,
24
24
  } = require("@saltcorn/markup/tags");
25
25
  const { radio_group, checkbox_group } = require("@saltcorn/markup/helpers");
26
+ const { picked_fields_to_query } = require("@saltcorn/data/plugin-helper");
26
27
  const moment = require("moment");
27
28
 
28
29
  const get_state_fields = () => [
@@ -49,7 +50,23 @@ const configuration_workflow = (req) =>
49
50
  state_fields.some((sf) => sf.name === "id")
50
51
  );
51
52
  const show_view_opts = show_views.map((v) => v.select_option);
53
+ let blurb;
54
+ if (table.provider_name)
55
+ blurb = [
56
+ div(
57
+ { class: "alert alert-danger fst-normal" },
58
+ `Use this view on a standard database table, not a provided table`
59
+ ),
60
+ ];
61
+ else if (!table.versioned)
62
+ blurb = [
63
+ div(
64
+ { class: "alert alert-danger fst-normal" },
65
+ `Version history is not enabled for this table`
66
+ ),
67
+ ];
52
68
  return new Form({
69
+ blurb,
53
70
  fields: [
54
71
  {
55
72
  name: "show_view",
@@ -70,6 +87,11 @@ const configuration_workflow = (req) =>
70
87
  options: show_view_opts,
71
88
  },
72
89
  },
90
+ {
91
+ name: "comparison",
92
+ label: "Side-by-side comparison",
93
+ type: "Bool",
94
+ },
73
95
  {
74
96
  name: "min_interval_secs",
75
97
  label: "Minimum interval (s)",
@@ -91,7 +113,7 @@ const configuration_workflow = (req) =>
91
113
  const run = async (
92
114
  table_id,
93
115
  viewname,
94
- { show_view, min_interval_secs, date_format },
116
+ { show_view, min_interval_secs, date_format, comparison },
95
117
  state,
96
118
  extraArgs
97
119
  ) => {
@@ -104,29 +126,55 @@ const run = async (
104
126
 
105
127
  let hist = await table.get_history(id);
106
128
 
129
+ if (!hist || !hist.length) return "No versions recorded";
130
+
107
131
  let last = 0;
108
132
  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
133
 
122
- if (!hist || !hist.length) return "No versions recorded";
123
- hist = hist.reverse();
134
+ hist = hist
135
+ .filter((row) => {
136
+ const myEpoch = Math.round(new Date(row._time).getTime() / 1000);
137
+ if (
138
+ myEpoch - last > min_interval_secs ||
139
+ (row._userid && row._userid !== last_changed_by)
140
+ ) {
141
+ //include
142
+ last = myEpoch;
143
+ last_changed_by = row._userid;
144
+ return true;
145
+ } else return false;
146
+ })
147
+ .reverse();
148
+ const view = View.findOne({ name: show_view });
149
+
150
+ const { joinFields } = picked_fields_to_query(
151
+ view.configuration.columns,
152
+ table.fields,
153
+ view.configurationlayout,
154
+ extraArgs.req,
155
+ table
156
+ );
157
+ for (const [nm, jf] of Object.entries(joinFields)) {
158
+ const refVals = new Set(hist.map((r) => r[jf.ref]));
159
+ const refField = table.getField(jf.ref);
160
+ const reftable = Table.findOne(refField.reftable_name);
161
+ const rows = await reftable.getRows({
162
+ id: { in: [...refVals] },
163
+ });
164
+ const rowsByVal = {};
165
+ rows.forEach((r) => {
166
+ rowsByVal[r[reftable.pk_name]] = r;
167
+ });
168
+
169
+ hist.forEach((h) => {
170
+ h[nm] = rowsByVal[h[jf.ref]]?.[jf.target];
171
+ });
172
+ }
124
173
 
125
174
  const userIds = new Set(hist.map((h) => h._userid));
126
175
  const users = await User.find({ id: { in: [...userIds] } });
127
176
  const emails = {};
128
177
  users.forEach((u) => (emails[u.id] = u.email));
129
- const view = View.findOne({ name: show_view });
130
178
  const rendered = await view.viewtemplateObj.renderRows(
131
179
  table,
132
180
  view.name,
@@ -169,7 +217,17 @@ const run = async (
169
217
  "aria-labelledby": `a${stateHash}head${ix}`,
170
218
  "data-bs-parent": `#top${stateHash}`,
171
219
  },
172
- div({ class: ["accordion-body"] }, html)
220
+ div(
221
+ { class: ["accordion-body"] },
222
+ comparison && ix < rendered.length - 1
223
+ ? div(
224
+ { class: "d-flex align-middle" },
225
+ div({ class: "border p-1 m-1" }, rendered[ix + 1]),
226
+ i({ class: "m-2 fas fa-arrow-right" }),
227
+ div({ class: "border p-1 m-1" }, html)
228
+ )
229
+ : html
230
+ )
173
231
  )
174
232
  );
175
233
  })