Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions acumate-plugin/src/backend-metadata-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,20 @@ export function buildBackendViewMap(structure: GraphStructure | undefined): Map<
continue;
}

const metadata: BackendViewMetadata = {
viewName: view.name ?? key,
normalizedName: lookupKey,
view,
fields: buildBackendFieldMap(view),
};
let metadata = views.get(lookupKey);
if (!metadata) {
metadata = {
viewName: view.name ?? key,
normalizedName: lookupKey,
view,
fields: buildBackendFieldMap(view),
};
views.set(lookupKey, metadata);
} else {
mergeBackendFields(metadata.fields, view);
}

views.set(lookupKey, metadata);
if (normalizedKey && normalizedKey !== lookupKey && !views.has(normalizedKey)) {
if (normalizedKey && !views.has(normalizedKey)) {
views.set(normalizedKey, metadata);
}
}
Expand Down Expand Up @@ -132,3 +137,12 @@ export function buildBackendFieldMap(view: View | undefined): Map<string, Backen

return fields;
}

function mergeBackendFields(target: Map<string, BackendFieldMetadata>, sourceView: View) {
const incomingFields = buildBackendFieldMap(sourceView);
for (const [fieldKey, fieldMetadata] of incomingFields) {
if (!target.has(fieldKey)) {
target.set(fieldKey, fieldMetadata);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
<field name="AMEstimateQty" append="#missing-target"></field>
<field name="AMInvalidSelector" move="#fsOrderTotals-Totals [name='CuryGoodsExtPriceTotal'"></field>
<field name="AMUnknownField" before="#fsCalculatedAmounts-Totals [name='BlanketOpenQty']"></field>
<qp-tab id="tab-Move" after="#tab-PutAway111"></qp-tab>
</template>
45 changes: 45 additions & 0 deletions acumate-plugin/src/test/suite/backendMetadata.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as assert from 'assert';
import { describe, it } from 'mocha';
import { buildBackendViewMap } from '../../backend-metadata-utils';
import { GraphStructure } from '../../model/graph-structure';
import { View } from '../../model/view';

describe('backend metadata utilities', () => {
it('merges duplicate backend views and preserves the first metadata instance', () => {
const baseTransactionsView: View = {
name: 'transactions',
cacheName: 'Purchase Receipt Line',
cacheType: 'POReceiptLine',
fields: {
ReceiptNbr: { name: 'ReceiptNbr' },
},
};

const secondaryTransactionsView: View = {
name: 'Transactions',
cacheName: 'Purchase Receipt Line (Alt)',
cacheType: 'POReceiptLine',
fields: {
ReceiptDate: { name: 'ReceiptDate' },
},
};

const structure: GraphStructure = {
name: 'PX.Objects.PO.POReceiptEntry',
views: {
transactions: baseTransactionsView,
transactionsPOLine: secondaryTransactionsView,
},
};

const backendViewMap = buildBackendViewMap(structure);
const canonical = backendViewMap.get('transactions');
assert.ok(canonical, 'Expected canonical transactions view metadata');
assert.strictEqual(canonical.view, baseTransactionsView, 'First view definition should be preserved');
assert.ok(canonical.fields.has('receiptnbr'), 'Original field should remain');
assert.ok(canonical.fields.has('receiptdate'), 'Fields from duplicate view should be merged');

const aliasMetadata = backendViewMap.get('transactionspoline');
assert.strictEqual(aliasMetadata, canonical, 'Alternate view keys should reference the canonical metadata');
});
});
10 changes: 10 additions & 0 deletions acumate-plugin/src/test/suite/htmlValidation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,16 @@ describe('HTML validation diagnostics', () => {
);
});

it('validates customization selectors on non-field elements', async () => {
const document = await vscode.workspace.openTextDocument(screenSelectorExtensionFixture);
await validateHtmlFile(document);
const diagnostics = AcuMateContext.HtmlValidator?.get(document.uri) ?? [];
assert.ok(
diagnostics.some(d => d.message.includes('after selector') && d.message.includes('tab-PutAway111')),
'Expected diagnostic when qp-tab after selector targets missing element'
);
});

it('derives view metadata from selector targets when <field> lacks a parent view', async () => {
const document = await vscode.workspace.openTextDocument(screenSelectorExtensionFixture);
await validateHtmlFile(document);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ function validateDom(
: `The <${node.name}> element must define an id attribute.`;
pushHtmlDiagnostic(diagnostics, suppression, range, message);
}

validateCustomizationSelectors(node);
}

if (
Expand Down Expand Up @@ -292,10 +294,6 @@ function validateDom(
validateConfigBinding(node.attribs["config.bind"], node);
}

if (node.type === "tag" && node.name === "field") {
validateFieldCustomizationSelectors(node);
}

if (
node.type === "tag" &&
(node.name === "field" || node.name === "qp-field") &&
Expand Down Expand Up @@ -387,7 +385,7 @@ function validateDom(
}
}

function validateFieldCustomizationSelectors(node: any) {
function validateCustomizationSelectors(node: any) {
if (!baseScreenDocument) {
return;
}
Expand Down