Bläddra i källkod

fix tabulator issue

main
Daniel Covington 1 vecka sedan
förälder
incheckning
009f61de3d
2 ändrade filer med 58 tillägg och 43 borttagningar
  1. +3
    -1
      .claude/settings.local.json
  2. +55
    -42
      public/js/app.js

+ 3
- 1
.claude/settings.local.json Visa fil

@@ -17,7 +17,9 @@
"PowerShell(Get-ChildItem -Path \"d:\\\\Development\\\\PHP\\\\Campaign-Tracker\" -Recurse -Directory -ErrorAction SilentlyContinue | Select-Object -First 30 | ForEach-Object { $_.FullName })",
"Skill(graphify)",
"PowerShell(python -c $script)",
"PowerShell(python .graphify_query.py)"
"PowerShell(python .graphify_query.py)",
"Bash(docker compose *)",
"Bash(node --check public/js/app.js)"
]
}
}

+ 55
- 42
public/js/app.js Visa fil

@@ -55,6 +55,51 @@ function _tabulatorPersistenceKey(key) {
return 'ct.tabulator.' + key;
}

// Builds a stable Tabulator field name for a dynamic attribute column, derived from the
// attribute's name rather than its position. This keeps persisted column order, width,
// visibility, and filters tied to the same attribute across page loads, even when the
// set/order of attributes discovered from the result rows changes.
function _attributeFieldKey(name, usedFields) {
let slug = String(name).toLowerCase().trim().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '');
if (slug === '') {
slug = 'field';
}

const base = 'attr__' + slug;
let key = base;
let suffix = 2;
while (usedFields.has(key)) {
key = base + '_' + suffix;
suffix++;
}

usedFields.add(key);
return key;
}

// Discovers the unique set of dynamic attributes across a list of rows, assigning each
// a stable `field` name (see _attributeFieldKey) for use as a Tabulator column field.
function _discoverAttributeColumns(rows, typeAttributesField, normalizeFn) {
const attributes = [];
const usedFields = new Set();

rows.forEach((row) => {
normalizeFn(row[typeAttributesField] || []).forEach((attr) => {
if (!attributes.some((existing) => existing.name === attr.name)) {
attributes.push({ ...attr, field: _attributeFieldKey(attr.name, usedFields) });
}
});

Object.keys(row.attribute_values || {}).forEach((name) => {
if (!attributes.some((existing) => existing.name === name)) {
attributes.push({ name: name, type: 'text', order: attributes.length + 1, field: _attributeFieldKey(name, usedFields) });
}
});
});

return attributes;
}

function _tabulatorBaseOptions(persistenceKey) {
return {
persistence: {
@@ -528,23 +573,7 @@ window.campaignTable = function () {
},

jobAttributeColumnsForRows(rows) {
const attributes = [];

rows.forEach((row) => {
this.normalizeAttributes(row.job_type_attributes || []).forEach((attr) => {
if (!attributes.some((existing) => existing.name === attr.name)) {
attributes.push(attr);
}
});

Object.keys(row.attribute_values || {}).forEach((name) => {
if (!attributes.some((existing) => existing.name === name)) {
attributes.push({ name: name, type: 'text', order: attributes.length + 1 });
}
});
});

return attributes;
return _discoverAttributeColumns(rows, 'job_type_attributes', this.normalizeAttributes);
},

formatJobRows(rows, attributes) {
@@ -560,8 +589,8 @@ window.campaignTable = function () {
edit_url: '/jobs/' + encodeURIComponent(row.id) + '/edit',
};

attributes.forEach((attr, index) => {
tableRow['job_attr_' + index] = this.formatAttributeValue(attributeValues[attr.name] ?? '');
attributes.forEach((attr) => {
tableRow[attr.field] = this.formatAttributeValue(attributeValues[attr.name] ?? '');
});

return tableRow;
@@ -586,10 +615,10 @@ window.campaignTable = function () {
{ title: 'Job Type', field: 'job_type_name', minWidth: 160, headerFilter: 'input' },
];

attributes.forEach((attr, index) => {
attributes.forEach((attr) => {
columns.push({
title: attr.name,
field: 'job_attr_' + index,
field: attr.field,
minWidth: 150,
headerFilter: 'input',
formatter: function (cell) {
@@ -1440,23 +1469,7 @@ window.jobTable = function () {
},

attributeColumnsForRows(rows) {
const attributes = [];

rows.forEach((row) => {
this.normalizeAttributes(row.job_type_attributes || []).forEach((attr) => {
if (!attributes.some((existing) => existing.name === attr.name)) {
attributes.push(attr);
}
});

Object.keys(row.attribute_values || {}).forEach((name) => {
if (!attributes.some((existing) => existing.name === name)) {
attributes.push({ name: name, type: 'text', order: attributes.length + 1 });
}
});
});

return attributes;
return _discoverAttributeColumns(rows, 'job_type_attributes', this.normalizeAttributes);
},

normalizeAttributes(attributes) {
@@ -1480,8 +1493,8 @@ window.jobTable = function () {
updated_at: row.updated_at || '',
};

attributes.forEach((attr, index) => {
tableRow['attr_' + index] = this.formatAttributeValue(attributeValues[attr.name] ?? '');
attributes.forEach((attr) => {
tableRow[attr.field] = this.formatAttributeValue(attributeValues[attr.name] ?? '');
});

return tableRow;
@@ -1520,10 +1533,10 @@ window.jobTable = function () {
{ title: 'Job Type', field: 'job_type_name', minWidth: 160, headerFilter: 'input' },
];

attributes.forEach((attr, index) => {
attributes.forEach((attr) => {
columns.push({
title: attr.name,
field: 'attr_' + index,
field: attr.field,
minWidth: 150,
headerFilter: 'input',
formatter: function (cell) {


Laddar…
Avbryt
Spara

Powered by TurnKey Linux.