Stop a segment edit from wiping its annotations
PUT /versions/:id/baseline/:logid deletes the log row and inserts a fresh one from the stored template, so every field the form does not send comes back null. That took the label and the bucket with it, and the tag besides -- the segment form has no tag input at all, so a tag could not survive an edit made for any other reason. The route now hands back what it was not given, reading the row it is about to replace. `??` rather than `||`: an empty string is the form clearing a field deliberately, undefined is the form not carrying it. The load templates gained a tag token to receive it. Stored templates are per-source and were generated before any of this existed, which is the other half of why labels vanished -- source 14's had no label column to write to. Regenerated. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3162759f93
commit
2306315a17
@ -8,7 +8,7 @@
|
|||||||
// Tokens baked in at generation time: column names, source schema.table
|
// Tokens baked in at generation time: column names, source schema.table
|
||||||
// Tokens substituted at request time: {{fc_table}}, {{where_clause}}, {{exclude_clause}},
|
// Tokens substituted at request time: {{fc_table}}, {{where_clause}}, {{exclude_clause}},
|
||||||
// {{version_id}}, {{logid}}, {{pf_user}}, {{note}},
|
// {{version_id}}, {{logid}}, {{pf_user}}, {{note}},
|
||||||
// {{label}}, {{bucket}},
|
// {{label}}, {{bucket}}, {{tag}},
|
||||||
// {{params}}, {{slice}}, {{date_from}}, {{date_to}},
|
// {{params}}, {{slice}}, {{date_from}}, {{date_to}},
|
||||||
// {{value_incr}}, {{units_incr}}, {{set_clause}}, {{scale_factor}}
|
// {{value_incr}}, {{units_incr}}, {{set_clause}}, {{scale_factor}}
|
||||||
|
|
||||||
@ -303,9 +303,9 @@ GROUP BY
|
|||||||
return `
|
return `
|
||||||
WITH
|
WITH
|
||||||
ilog AS (
|
ilog AS (
|
||||||
INSERT INTO pf.log (version_id, pf_user, operation, slice, params, note, label, bucket)
|
INSERT INTO pf.log (version_id, pf_user, operation, slice, params, note, label, bucket, tag)
|
||||||
VALUES ({{version_id}}, '{{pf_user}}', 'baseline', NULL, '{{params}}'::jsonb, '{{note}}',
|
VALUES ({{version_id}}, '{{pf_user}}', 'baseline', NULL, '{{params}}'::jsonb, '{{note}}',
|
||||||
NULLIF('{{label}}', ''), NULLIF('{{bucket}}', ''))
|
NULLIF('{{label}}', ''), NULLIF('{{bucket}}', ''), NULLIF('{{tag}}', ''))
|
||||||
RETURNING id
|
RETURNING id
|
||||||
)
|
)
|
||||||
,ins AS (
|
,ins AS (
|
||||||
@ -324,9 +324,9 @@ SELECT count(*) AS rows_affected FROM ins`.trim();
|
|||||||
return `
|
return `
|
||||||
WITH
|
WITH
|
||||||
ilog AS (
|
ilog AS (
|
||||||
INSERT INTO pf.log (version_id, pf_user, operation, slice, params, note, label, bucket)
|
INSERT INTO pf.log (version_id, pf_user, operation, slice, params, note, label, bucket, tag)
|
||||||
VALUES ({{version_id}}, '{{pf_user}}', 'reference', NULL, '{{params}}'::jsonb, '{{note}}',
|
VALUES ({{version_id}}, '{{pf_user}}', 'reference', NULL, '{{params}}'::jsonb, '{{note}}',
|
||||||
NULLIF('{{label}}', ''), NULLIF('{{bucket}}', ''))
|
NULLIF('{{label}}', ''), NULLIF('{{bucket}}', ''), NULLIF('{{tag}}', ''))
|
||||||
RETURNING id
|
RETURNING id
|
||||||
)
|
)
|
||||||
,ins AS (
|
,ins AS (
|
||||||
|
|||||||
@ -409,7 +409,7 @@ module.exports = function(pool) {
|
|||||||
|
|
||||||
// load baseline rows from source table — additive, no delete
|
// load baseline rows from source table — additive, no delete
|
||||||
router.post('/versions/:id/baseline', async (req, res) => {
|
router.post('/versions/:id/baseline', async (req, res) => {
|
||||||
const { where_clause, date_offset, note, filters, raw_where, label, bucket } = req.body;
|
const { where_clause, date_offset, note, filters, raw_where, label, bucket, tag } = req.body;
|
||||||
const pf_user = sessionUser(req);
|
const pf_user = sessionUser(req);
|
||||||
const dateOffset = date_offset || '0 days';
|
const dateOffset = date_offset || '0 days';
|
||||||
if (!await assertInterval(dateOffset, res)) return;
|
if (!await assertInterval(dateOffset, res)) return;
|
||||||
@ -429,6 +429,7 @@ module.exports = function(pool) {
|
|||||||
note: esc(note || ''),
|
note: esc(note || ''),
|
||||||
label: esc(label || ''),
|
label: esc(label || ''),
|
||||||
bucket: esc(bucket || ''),
|
bucket: esc(bucket || ''),
|
||||||
|
tag: esc(tag || ''),
|
||||||
params: esc(paramsJson),
|
params: esc(paramsJson),
|
||||||
filter_clause: filterClause,
|
filter_clause: filterClause,
|
||||||
date_offset: esc(dateOffset)
|
date_offset: esc(dateOffset)
|
||||||
@ -448,7 +449,7 @@ module.exports = function(pool) {
|
|||||||
router.put('/versions/:id/baseline/:logid', async (req, res) => {
|
router.put('/versions/:id/baseline/:logid', async (req, res) => {
|
||||||
const versionId = parseInt(req.params.id);
|
const versionId = parseInt(req.params.id);
|
||||||
const logid = parseInt(req.params.logid);
|
const logid = parseInt(req.params.logid);
|
||||||
const { where_clause, date_offset, note, filters, raw_where, label, bucket } = req.body;
|
const { where_clause, date_offset, note, filters, raw_where, label, bucket, tag } = req.body;
|
||||||
const pf_user = sessionUser(req);
|
const pf_user = sessionUser(req);
|
||||||
const dateOffset = date_offset || '0 days';
|
const dateOffset = date_offset || '0 days';
|
||||||
if (!await assertInterval(dateOffset, res)) return;
|
if (!await assertInterval(dateOffset, res)) return;
|
||||||
@ -487,13 +488,21 @@ module.exports = function(pool) {
|
|||||||
date_offset: dateOffset,
|
date_offset: dateOffset,
|
||||||
...(raw_where ? { raw_where } : (filters ? { filters } : {}))
|
...(raw_where ? { raw_where } : (filters ? { filters } : {}))
|
||||||
});
|
});
|
||||||
|
// This route deletes the log row and inserts a fresh one, so every
|
||||||
|
// annotation on it has to be handed back or it is lost. `??`, not `||`:
|
||||||
|
// an empty string is the form clearing a field on purpose, undefined is
|
||||||
|
// the form not carrying it at all -- the segment form has no tag input,
|
||||||
|
// so tag is always the latter and must survive an edit made for any
|
||||||
|
// other reason.
|
||||||
|
const keep = (sent, prior) => esc(sent ?? prior ?? '');
|
||||||
const sql = applyTokens(ctx.sql, {
|
const sql = applyTokens(ctx.sql, {
|
||||||
fc_table: ctx.table,
|
fc_table: ctx.table,
|
||||||
version_id: ctx.version.id,
|
version_id: ctx.version.id,
|
||||||
pf_user: esc(pf_user || ''),
|
pf_user: esc(pf_user || ''),
|
||||||
note: esc(note || ''),
|
note: esc(note || ''),
|
||||||
label: esc(label || ''),
|
label: keep(label, oldLog.label),
|
||||||
bucket: esc(bucket || ''),
|
bucket: keep(bucket, oldLog.bucket),
|
||||||
|
tag: keep(tag, oldLog.tag),
|
||||||
params: esc(paramsJson),
|
params: esc(paramsJson),
|
||||||
filter_clause: filterClause,
|
filter_clause: filterClause,
|
||||||
date_offset: esc(dateOffset)
|
date_offset: esc(dateOffset)
|
||||||
@ -558,7 +567,7 @@ module.exports = function(pool) {
|
|||||||
|
|
||||||
// load reference rows from source table (additive — does not clear prior reference rows)
|
// load reference rows from source table (additive — does not clear prior reference rows)
|
||||||
router.post('/versions/:id/reference', async (req, res) => {
|
router.post('/versions/:id/reference', async (req, res) => {
|
||||||
const { where_clause, date_offset, note, filters, raw_where, label, bucket } = req.body;
|
const { where_clause, date_offset, note, filters, raw_where, label, bucket, tag } = req.body;
|
||||||
const pf_user = sessionUser(req);
|
const pf_user = sessionUser(req);
|
||||||
const dateOffset = date_offset || '0 days';
|
const dateOffset = date_offset || '0 days';
|
||||||
const filterClause = (raw_where || where_clause || '').trim() || 'TRUE';
|
const filterClause = (raw_where || where_clause || '').trim() || 'TRUE';
|
||||||
@ -577,6 +586,7 @@ module.exports = function(pool) {
|
|||||||
note: esc(note || ''),
|
note: esc(note || ''),
|
||||||
label: esc(label || ''),
|
label: esc(label || ''),
|
||||||
bucket: esc(bucket || ''),
|
bucket: esc(bucket || ''),
|
||||||
|
tag: esc(tag || ''),
|
||||||
params: esc(paramsJson),
|
params: esc(paramsJson),
|
||||||
filter_clause: filterClause,
|
filter_clause: filterClause,
|
||||||
date_offset: esc(dateOffset)
|
date_offset: esc(dateOffset)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user