@olenbetong/appframe-core 2.16.0 → 2.16.1
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/dist/esm/af.common.js +24 -12
- package/dist/esm/af.common.legacy.js +15 -3
- package/dist/esm/af.common.legacy.min.js +3 -3
- package/dist/esm/af.common.legacy.min.js.map +1 -1
- package/dist/esm/af.common.min.js +3 -3
- package/dist/esm/af.common.min.js.map +1 -1
- package/dist/iife/af.common.js +24 -12
- package/dist/iife/af.common.legacy.js +15 -3
- package/dist/iife/af.common.legacy.min.js +3 -3
- package/dist/iife/af.common.legacy.min.js.map +1 -1
- package/dist/iife/af.common.min.js +3 -3
- package/dist/iife/af.common.min.js.map +1 -1
- package/es/index.js +1 -1
- package/es/report/recordSource.d.ts +1 -1
- package/es/report/recordSource.js +16 -2
- package/es/report/report.test.js +36 -0
- package/package.json +2 -2
- package/src/report/recordSource.ts +17 -2
- package/src/report/report.test.ts +39 -0
package/es/index.js
CHANGED
|
@@ -19,4 +19,4 @@ export { UserSession };
|
|
|
19
19
|
export { alert, ConfirmButtons, confirm, openAlertDialog, waitForDialog } from "./alert.js";
|
|
20
20
|
export { getSettings, saveSettings } from "./settings.js";
|
|
21
21
|
// oxlint-disable-next-line no-use-before-define -- this is injected build time
|
|
22
|
-
export const version = "2.
|
|
22
|
+
export const version = "2.16.1";
|
|
@@ -27,4 +27,4 @@ export declare function readElements(xml: string, name: string): string[];
|
|
|
27
27
|
* Returns `null` for anything that is not a record source, so a missing or
|
|
28
28
|
* empty `RecordSource` column simply means "no lookup".
|
|
29
29
|
*/
|
|
30
|
-
export declare function parseRecordSource(
|
|
30
|
+
export declare function parseRecordSource(document: string | null | undefined): ReportRecordSource | null;
|
|
@@ -80,6 +80,19 @@ function readSelectColumns(xml) {
|
|
|
80
80
|
}
|
|
81
81
|
return columns;
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* The record source a document holds. Parameter lookups store one `<afRecordSource>`; a report
|
|
85
|
+
* stores its record sources as `<ArrayOfAfReportRecordSource>` with one `<afReportRecordSource>`
|
|
86
|
+
* per data source, of which the one with the ID `Master` feeds the report (else the first).
|
|
87
|
+
*/
|
|
88
|
+
function pickRecordSource(document) {
|
|
89
|
+
if (!document)
|
|
90
|
+
return null;
|
|
91
|
+
let sources = [...document.matchAll(/<(afRecordSource|afReportRecordSource)(?:\s[^>]*)?>([\s\S]*?)<\/\1>/g)].map((match) => match[2]);
|
|
92
|
+
if (sources.length === 0)
|
|
93
|
+
return null;
|
|
94
|
+
return sources.find((source) => readElement(source, "ID") === "Master") ?? sources[0];
|
|
95
|
+
}
|
|
83
96
|
/**
|
|
84
97
|
* Reads the parts of an `afRecordSource` a web client can act on: the view, the
|
|
85
98
|
* selected columns and the design-time filter.
|
|
@@ -87,8 +100,9 @@ function readSelectColumns(xml) {
|
|
|
87
100
|
* Returns `null` for anything that is not a record source, so a missing or
|
|
88
101
|
* empty `RecordSource` column simply means "no lookup".
|
|
89
102
|
*/
|
|
90
|
-
export function parseRecordSource(
|
|
91
|
-
|
|
103
|
+
export function parseRecordSource(document) {
|
|
104
|
+
let xml = pickRecordSource(document);
|
|
105
|
+
if (!xml)
|
|
92
106
|
return null;
|
|
93
107
|
let viewName = readElement(xml, "ViewName");
|
|
94
108
|
if (!viewName)
|
package/es/report/report.test.js
CHANGED
|
@@ -36,6 +36,42 @@ describe("parseRecordSource", () => {
|
|
|
36
36
|
let xml = recordSource.replace("[Level] = 1", "[Name] Like '%a & b%'");
|
|
37
37
|
expect(parseRecordSource(xml)?.filterString).toBe("[Name] Like '%a & b%'");
|
|
38
38
|
});
|
|
39
|
+
it("reads a report's record sources, taking the master one", () => {
|
|
40
|
+
let report = `<?xml version="1.0" encoding="utf-16"?>
|
|
41
|
+
<ArrayOfAfReportRecordSource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
42
|
+
<afReportRecordSource>
|
|
43
|
+
<ViewName>aviw_Production_ElementsSub</ViewName>
|
|
44
|
+
<FilterString />
|
|
45
|
+
<ID>Sub</ID>
|
|
46
|
+
</afReportRecordSource>
|
|
47
|
+
<afReportRecordSource>
|
|
48
|
+
<IsFilterChanging>false</IsFilterChanging>
|
|
49
|
+
<ViewName>aviw_Production_ElementsProductionPerCutOffWithPrevious</ViewName>
|
|
50
|
+
<SelectColumns>
|
|
51
|
+
<afSelectColumn><Name>ProjectID</Name></afSelectColumn>
|
|
52
|
+
<afSelectColumn><Name>Area</Name><DataType>Decimal</DataType></afSelectColumn>
|
|
53
|
+
</SelectColumns>
|
|
54
|
+
<WhereClause>[Type] = 'Element'</WhereClause>
|
|
55
|
+
<FilterString>[ProjectID] = 'PT19-1004' AND [Period] = '2021-49'</FilterString>
|
|
56
|
+
<MaxRecords>0</MaxRecords>
|
|
57
|
+
<ID>Master</ID>
|
|
58
|
+
</afReportRecordSource>
|
|
59
|
+
</ArrayOfAfReportRecordSource>`;
|
|
60
|
+
expect(parseRecordSource(report)).toEqual({
|
|
61
|
+
viewName: "aviw_Production_ElementsProductionPerCutOffWithPrevious",
|
|
62
|
+
columns: [
|
|
63
|
+
{ name: "ProjectID", type: "string" },
|
|
64
|
+
{ name: "Area", type: "number" },
|
|
65
|
+
],
|
|
66
|
+
whereClause: "[Type] = 'Element'",
|
|
67
|
+
filterString: "[ProjectID] = 'PT19-1004' AND [Period] = '2021-49'",
|
|
68
|
+
maxRecords: null,
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
it("takes the first record source when none is the master", () => {
|
|
72
|
+
let report = `<ArrayOfAfReportRecordSource><afReportRecordSource><ViewName>aviw_A</ViewName></afReportRecordSource><afReportRecordSource><ViewName>aviw_B</ViewName></afReportRecordSource></ArrayOfAfReportRecordSource>`;
|
|
73
|
+
expect(parseRecordSource(report)?.viewName).toBe("aviw_A");
|
|
74
|
+
});
|
|
39
75
|
it("returns nothing for anything that is not a record source", () => {
|
|
40
76
|
expect(parseRecordSource(null)).toBeNull();
|
|
41
77
|
expect(parseRecordSource("")).toBeNull();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olenbetong/appframe-core",
|
|
3
|
-
"version": "2.16.
|
|
3
|
+
"version": "2.16.1",
|
|
4
4
|
"description": "Javascript libraries to utilize the Appframe framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@types/bun": "^1.4.4",
|
|
45
45
|
"chalk": "^6.0.1",
|
|
46
46
|
"typescript": "7.0.2",
|
|
47
|
-
"vitest": "5.0
|
|
47
|
+
"vitest": "5.1.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {},
|
|
50
50
|
"optionalDependencies": {},
|
|
@@ -97,6 +97,20 @@ function readSelectColumns(xml: string): ReportRecordSourceColumn[] {
|
|
|
97
97
|
return columns;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* The record source a document holds. Parameter lookups store one `<afRecordSource>`; a report
|
|
102
|
+
* stores its record sources as `<ArrayOfAfReportRecordSource>` with one `<afReportRecordSource>`
|
|
103
|
+
* per data source, of which the one with the ID `Master` feeds the report (else the first).
|
|
104
|
+
*/
|
|
105
|
+
function pickRecordSource(document: string | null | undefined): string | null {
|
|
106
|
+
if (!document) return null;
|
|
107
|
+
let sources = [...document.matchAll(/<(afRecordSource|afReportRecordSource)(?:\s[^>]*)?>([\s\S]*?)<\/\1>/g)].map(
|
|
108
|
+
(match) => match[2],
|
|
109
|
+
);
|
|
110
|
+
if (sources.length === 0) return null;
|
|
111
|
+
return sources.find((source) => readElement(source, "ID") === "Master") ?? sources[0];
|
|
112
|
+
}
|
|
113
|
+
|
|
100
114
|
/**
|
|
101
115
|
* Reads the parts of an `afRecordSource` a web client can act on: the view, the
|
|
102
116
|
* selected columns and the design-time filter.
|
|
@@ -104,8 +118,9 @@ function readSelectColumns(xml: string): ReportRecordSourceColumn[] {
|
|
|
104
118
|
* Returns `null` for anything that is not a record source, so a missing or
|
|
105
119
|
* empty `RecordSource` column simply means "no lookup".
|
|
106
120
|
*/
|
|
107
|
-
export function parseRecordSource(
|
|
108
|
-
|
|
121
|
+
export function parseRecordSource(document: string | null | undefined): ReportRecordSource | null {
|
|
122
|
+
let xml = pickRecordSource(document);
|
|
123
|
+
if (!xml) return null;
|
|
109
124
|
|
|
110
125
|
let viewName = readElement(xml, "ViewName");
|
|
111
126
|
if (!viewName) return null;
|
|
@@ -47,6 +47,45 @@ describe("parseRecordSource", () => {
|
|
|
47
47
|
expect(parseRecordSource(xml)?.filterString).toBe("[Name] Like '%a & b%'");
|
|
48
48
|
});
|
|
49
49
|
|
|
50
|
+
it("reads a report's record sources, taking the master one", () => {
|
|
51
|
+
let report = `<?xml version="1.0" encoding="utf-16"?>
|
|
52
|
+
<ArrayOfAfReportRecordSource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
53
|
+
<afReportRecordSource>
|
|
54
|
+
<ViewName>aviw_Production_ElementsSub</ViewName>
|
|
55
|
+
<FilterString />
|
|
56
|
+
<ID>Sub</ID>
|
|
57
|
+
</afReportRecordSource>
|
|
58
|
+
<afReportRecordSource>
|
|
59
|
+
<IsFilterChanging>false</IsFilterChanging>
|
|
60
|
+
<ViewName>aviw_Production_ElementsProductionPerCutOffWithPrevious</ViewName>
|
|
61
|
+
<SelectColumns>
|
|
62
|
+
<afSelectColumn><Name>ProjectID</Name></afSelectColumn>
|
|
63
|
+
<afSelectColumn><Name>Area</Name><DataType>Decimal</DataType></afSelectColumn>
|
|
64
|
+
</SelectColumns>
|
|
65
|
+
<WhereClause>[Type] = 'Element'</WhereClause>
|
|
66
|
+
<FilterString>[ProjectID] = 'PT19-1004' AND [Period] = '2021-49'</FilterString>
|
|
67
|
+
<MaxRecords>0</MaxRecords>
|
|
68
|
+
<ID>Master</ID>
|
|
69
|
+
</afReportRecordSource>
|
|
70
|
+
</ArrayOfAfReportRecordSource>`;
|
|
71
|
+
|
|
72
|
+
expect(parseRecordSource(report)).toEqual({
|
|
73
|
+
viewName: "aviw_Production_ElementsProductionPerCutOffWithPrevious",
|
|
74
|
+
columns: [
|
|
75
|
+
{ name: "ProjectID", type: "string" },
|
|
76
|
+
{ name: "Area", type: "number" },
|
|
77
|
+
],
|
|
78
|
+
whereClause: "[Type] = 'Element'",
|
|
79
|
+
filterString: "[ProjectID] = 'PT19-1004' AND [Period] = '2021-49'",
|
|
80
|
+
maxRecords: null,
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("takes the first record source when none is the master", () => {
|
|
85
|
+
let report = `<ArrayOfAfReportRecordSource><afReportRecordSource><ViewName>aviw_A</ViewName></afReportRecordSource><afReportRecordSource><ViewName>aviw_B</ViewName></afReportRecordSource></ArrayOfAfReportRecordSource>`;
|
|
86
|
+
expect(parseRecordSource(report)?.viewName).toBe("aviw_A");
|
|
87
|
+
});
|
|
88
|
+
|
|
50
89
|
it("returns nothing for anything that is not a record source", () => {
|
|
51
90
|
expect(parseRecordSource(null)).toBeNull();
|
|
52
91
|
expect(parseRecordSource("")).toBeNull();
|