jopi-toolkit 3.1.32 → 3.1.37
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/jk_app/common.d.ts +1 -0
- package/dist/jk_app/common.js +9 -2
- package/dist/jk_app/common.js.map +1 -1
- package/dist/jk_data/browserActions.d.ts +8 -0
- package/dist/jk_data/browserActions.js +9 -0
- package/dist/jk_data/browserActions.js.map +1 -0
- package/dist/jk_data/bundler_ifServer.d.ts +2 -0
- package/dist/jk_data/bundler_ifServer.js +2 -0
- package/dist/jk_data/bundler_ifServer.js.map +1 -0
- package/dist/jk_data/common.d.ts +8 -0
- package/dist/jk_data/common.js +2 -0
- package/dist/jk_data/common.js.map +1 -0
- package/dist/jk_data/core.d.ts +13 -0
- package/dist/jk_data/core.js +85 -0
- package/dist/jk_data/core.js.map +1 -0
- package/dist/jk_data/dataTableProxy.d.ts +21 -0
- package/dist/jk_data/dataTableProxy.js +49 -0
- package/dist/jk_data/dataTableProxy.js.map +1 -0
- package/dist/jk_data/ifServerSide.d.ts +0 -0
- package/dist/jk_data/ifServerSide.js +2 -0
- package/dist/jk_data/ifServerSide.js.map +1 -0
- package/dist/jk_data/index.d.ts +3 -55
- package/dist/jk_data/index.js +3 -105
- package/dist/jk_data/index.js.map +1 -1
- package/dist/jk_data/interfaces.d.ts +107 -0
- package/dist/jk_data/interfaces.js +2 -0
- package/dist/jk_data/interfaces.js.map +1 -0
- package/dist/jk_data/jBundler_common.d.ts +12 -0
- package/dist/jk_data/jBundler_common.js +2 -0
- package/dist/jk_data/jBundler_common.js.map +1 -0
- package/dist/jk_data/jBundler_ifBrowser.d.ts +2 -0
- package/dist/jk_data/jBundler_ifBrowser.js +2 -0
- package/dist/jk_data/jBundler_ifBrowser.js.map +1 -0
- package/dist/jk_data/jBundler_ifServer.1.d.ts +2 -0
- package/dist/jk_data/jBundler_ifServer.1.js +2 -0
- package/dist/jk_data/jBundler_ifServer.1.js.map +1 -0
- package/dist/jk_data/jBundler_ifServer.d.ts +2 -0
- package/dist/jk_data/jBundler_ifServer.js +2 -0
- package/dist/jk_data/jBundler_ifServer.js.map +1 -0
- package/dist/jk_data/proxy.d.ts +24 -0
- package/dist/jk_data/proxy.js +82 -0
- package/dist/jk_data/proxy.js.map +1 -0
- package/dist/jk_dates/index.d.ts +4 -0
- package/dist/jk_dates/index.js +11 -0
- package/dist/jk_dates/index.js.map +1 -0
- package/dist/jk_fs/jBundler_ifServer.d.ts +2 -0
- package/dist/jk_fs/jBundler_ifServer.js +11 -1
- package/dist/jk_fs/jBundler_ifServer.js.map +1 -1
- package/dist/jk_memcache/index.d.ts +1 -0
- package/dist/jk_memcache/index.js +1 -5
- package/dist/jk_memcache/index.js.map +1 -1
- package/dist/jk_schemas/index.d.ts +20 -16
- package/dist/jk_schemas/index.js +13 -15
- package/dist/jk_schemas/index.js.map +1 -1
- package/dist/jk_tools/index.d.ts +1 -0
- package/package.json +8 -3
- package/src/jk_app/common.ts +12 -2
- package/src/jk_data/core.ts +92 -0
- package/src/jk_data/index.ts +3 -166
- package/src/jk_data/interfaces.ts +140 -0
- package/src/jk_data/proxy.ts +102 -0
- package/src/jk_dates/index.ts +12 -0
- package/src/jk_fs/jBundler_ifServer.ts +11 -1
- package/src/jk_memcache/index.ts +4 -8
- package/src/jk_schemas/index.ts +29 -27
- package/src/jk_tools/index.ts +3 -1
- package/src/jk_compress/index.js +0 -1
- package/src/jk_compress/jBundler_ifServer.js +0 -10
- package/src/jk_data/index.js +0 -155
- package/src/jk_schemas/index.js +0 -330
package/src/jk_app/common.ts
CHANGED
|
@@ -291,12 +291,22 @@ export function getCompiledCodeDir(): string {
|
|
|
291
291
|
return rootDir;
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
+
export function toSourceCodeDir(itemPath: string): string {
|
|
295
|
+
const compiledDir = getCompiledCodeDir();
|
|
296
|
+
|
|
297
|
+
if (itemPath.startsWith(compiledDir)) {
|
|
298
|
+
return getSourceCodeDir() + itemPath.substring(compiledDir.length);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return itemPath;
|
|
302
|
+
}
|
|
303
|
+
|
|
294
304
|
export function getCompiledFilePathFor(sourceFilePath: string, replaceExtension = true): string {
|
|
295
305
|
const compiledCodeDir = getCompiledCodeDir();
|
|
296
306
|
const sourceCodeDir = getSourceCodeDir();
|
|
297
307
|
|
|
298
308
|
if (!sourceFilePath.startsWith(sourceCodeDir)) {
|
|
299
|
-
|
|
309
|
+
return sourceFilePath;
|
|
300
310
|
}
|
|
301
311
|
|
|
302
312
|
let filePath = sourceFilePath.substring(sourceCodeDir.length);
|
|
@@ -321,7 +331,7 @@ export function getSourcesCodePathFor(compiledFilePath: string): string {
|
|
|
321
331
|
const sourceCodeDir = getSourceCodeDir();
|
|
322
332
|
|
|
323
333
|
if (!compiledFilePath.startsWith(compiledCodeDir)) {
|
|
324
|
-
|
|
334
|
+
return compiledCodeDir;
|
|
325
335
|
}
|
|
326
336
|
|
|
327
337
|
let filePath = jk_fs.join(sourceCodeDir, compiledFilePath.substring(compiledCodeDir.length));
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {type Schema} from "jopi-toolkit/jk_schema";
|
|
2
|
+
import type { JopiDataTable, JDataReadParams, JDataReadResult, JRowArrayFilter } from "./interfaces.ts";
|
|
3
|
+
export * from "./interfaces.ts";
|
|
4
|
+
|
|
5
|
+
//region Rows Arrays
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Filter the row content according to rules.
|
|
9
|
+
*/
|
|
10
|
+
export function simpleRowArrayFilter(rows: any[], params: JRowArrayFilter): JDataReadResult {
|
|
11
|
+
// > Apply filter.
|
|
12
|
+
|
|
13
|
+
if (params.filter) {
|
|
14
|
+
const f = params.filter;
|
|
15
|
+
|
|
16
|
+
rows = rows.filter(r => {
|
|
17
|
+
if (f.field) {
|
|
18
|
+
let v = r[f.field];
|
|
19
|
+
if (v===undefined) return false;
|
|
20
|
+
return String(v).includes(f.value);
|
|
21
|
+
} else {
|
|
22
|
+
for (let v of Object.values(r)) {
|
|
23
|
+
if (v===undefined) continue;
|
|
24
|
+
if (String(v).includes(f.value)) return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// > Apply sorting.
|
|
33
|
+
|
|
34
|
+
if (params.sorting && params.sorting.length) {
|
|
35
|
+
const sorting = params.sorting[0];
|
|
36
|
+
const sortField = sorting.id;
|
|
37
|
+
const sortDesc = sorting.desc;
|
|
38
|
+
|
|
39
|
+
rows = rows.sort((a, b) => {
|
|
40
|
+
let av = a[sortField];
|
|
41
|
+
let bv = b[sortField];
|
|
42
|
+
|
|
43
|
+
if (av === undefined) av = "";
|
|
44
|
+
if (bv === undefined) bv = "";
|
|
45
|
+
|
|
46
|
+
const avIsNumber = typeof av === "number";
|
|
47
|
+
const bvIsNumber = typeof bv === "number";
|
|
48
|
+
|
|
49
|
+
if (avIsNumber && bvIsNumber) {
|
|
50
|
+
if (sortDesc) {
|
|
51
|
+
return bv - av;
|
|
52
|
+
} else {
|
|
53
|
+
return av - bv;
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
const avStr = String(av);
|
|
57
|
+
const bvStr = String(bv);
|
|
58
|
+
|
|
59
|
+
if (sortDesc) {
|
|
60
|
+
return bvStr.localeCompare(avStr);
|
|
61
|
+
} else {
|
|
62
|
+
return avStr.localeCompare(bvStr);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const totalWithoutPagination = rows.length;
|
|
69
|
+
let offset = 0;
|
|
70
|
+
|
|
71
|
+
if (params.page) {
|
|
72
|
+
offset = params.page.pageIndex * params.page.pageSize;
|
|
73
|
+
rows = rows.slice(offset, offset + params.page.pageSize);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {rows, total: totalWithoutPagination, offset};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
//endregion
|
|
80
|
+
|
|
81
|
+
//region JDataBinding
|
|
82
|
+
|
|
83
|
+
export class JDataBinding_UseArray implements JopiDataTable {
|
|
84
|
+
public constructor(public readonly schema: Schema, private readonly rows: any[]) {
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async read(params: JDataReadParams): Promise<JDataReadResult> {
|
|
88
|
+
return simpleRowArrayFilter(this.rows, params);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//endregion
|
package/src/jk_data/index.ts
CHANGED
|
@@ -1,166 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export interface JFieldSorting {
|
|
6
|
-
id: string;
|
|
7
|
-
desc: boolean;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface JFieldFilter {
|
|
11
|
-
value?: string | number | boolean;
|
|
12
|
-
constraint: JFieldConstraintType;
|
|
13
|
-
caseSensitive?: boolean;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export type JFieldConstraintType =
|
|
17
|
-
| "$eq" // Equals
|
|
18
|
-
| "$ne" // Not equals
|
|
19
|
-
| "$gt" // Greater than
|
|
20
|
-
| "$gte" // Greater than or equals
|
|
21
|
-
| "$lt" // Less than
|
|
22
|
-
| "$lte" // Less than or equals
|
|
23
|
-
| "$in" // In an array of values
|
|
24
|
-
| "$nin" // Not in an array of values
|
|
25
|
-
| "$like" // Like search %endsWith or startsWith%
|
|
26
|
-
|
|
27
|
-
export interface JRowsFilter {
|
|
28
|
-
field?: string;
|
|
29
|
-
value: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface JPageExtraction {
|
|
33
|
-
pageIndex: number;
|
|
34
|
-
pageSize: number;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface JRowArrayFilter {
|
|
38
|
-
page?: JPageExtraction;
|
|
39
|
-
filter?: JRowsFilter;
|
|
40
|
-
sorting?: JFieldSorting[];
|
|
41
|
-
fieldFilters?: Record<string, JFieldFilter[]>;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Filter the row content according to rules.
|
|
46
|
-
*/
|
|
47
|
-
export function simpleRowArrayFilter(rows: any[], params: JRowArrayFilter): JTableDs_ReadResult {
|
|
48
|
-
// > Apply filter.
|
|
49
|
-
|
|
50
|
-
if (params.filter) {
|
|
51
|
-
const f = params.filter;
|
|
52
|
-
|
|
53
|
-
rows = rows.filter(r => {
|
|
54
|
-
if (f.field) {
|
|
55
|
-
let v = r[f.field];
|
|
56
|
-
if (v===undefined) return false;
|
|
57
|
-
return String(v).includes(f.value);
|
|
58
|
-
} else {
|
|
59
|
-
for (let v of Object.values(r)) {
|
|
60
|
-
if (v===undefined) continue;
|
|
61
|
-
if (String(v).includes(f.value)) return true;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// > Apply sorting.
|
|
70
|
-
|
|
71
|
-
if (params.sorting && params.sorting.length) {
|
|
72
|
-
const sorting = params.sorting[0];
|
|
73
|
-
const sortField = sorting.id;
|
|
74
|
-
const sortDesc = sorting.desc;
|
|
75
|
-
|
|
76
|
-
rows = rows.sort((a, b) => {
|
|
77
|
-
let av = a[sortField];
|
|
78
|
-
let bv = b[sortField];
|
|
79
|
-
|
|
80
|
-
if (av === undefined) av = "";
|
|
81
|
-
if (bv === undefined) bv = "";
|
|
82
|
-
|
|
83
|
-
const avIsNumber = typeof av === "number";
|
|
84
|
-
const bvIsNumber = typeof bv === "number";
|
|
85
|
-
|
|
86
|
-
if (avIsNumber && bvIsNumber) {
|
|
87
|
-
if (sortDesc) {
|
|
88
|
-
return bv - av;
|
|
89
|
-
} else {
|
|
90
|
-
return av - bv;
|
|
91
|
-
}
|
|
92
|
-
} else {
|
|
93
|
-
const avStr = String(av);
|
|
94
|
-
const bvStr = String(bv);
|
|
95
|
-
|
|
96
|
-
if (sortDesc) {
|
|
97
|
-
return bvStr.localeCompare(avStr);
|
|
98
|
-
} else {
|
|
99
|
-
return avStr.localeCompare(bvStr);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const totalWithoutPagination = rows.length;
|
|
106
|
-
let offset = 0;
|
|
107
|
-
|
|
108
|
-
if (params.page) {
|
|
109
|
-
offset = params.page.pageIndex * params.page.pageSize;
|
|
110
|
-
rows = rows.slice(offset, offset + params.page.pageSize);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return {rows, total: totalWithoutPagination, offset};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
//endregion
|
|
117
|
-
|
|
118
|
-
//region JTableDs
|
|
119
|
-
|
|
120
|
-
export interface JTableDs_ReadParams extends JRowArrayFilter {
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export interface JTableDs_ReadResult {
|
|
124
|
-
rows: any[];
|
|
125
|
-
total?: number;
|
|
126
|
-
offset?: number;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export interface JTableDs {
|
|
130
|
-
get name(): string;
|
|
131
|
-
get schema(): Schema;
|
|
132
|
-
read(params: JTableDs_ReadParams): Promise<JTableDs_ReadResult>;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export class JTableDs_UseArray implements JTableDs {
|
|
136
|
-
public constructor(public readonly name: string, public readonly schema: Schema, private readonly rows: any[]) {
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
async read(params: JTableDs_ReadParams): Promise<JTableDs_ReadResult> {
|
|
140
|
-
return simpleRowArrayFilter(this.rows, params);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export class JTableDs_HttpProxy implements JTableDs {
|
|
145
|
-
public constructor(public readonly name: string, private readonly url: string, public readonly schema: Schema) {
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async read(params: JTableDs_ReadParams): Promise<JTableDs_ReadResult> {
|
|
149
|
-
let toSend = {dsName: this.name, read: params};
|
|
150
|
-
|
|
151
|
-
let res = await fetch(this.url, {
|
|
152
|
-
method: "POST",
|
|
153
|
-
headers: {"Content-Type": "application/json"},
|
|
154
|
-
body: JSON.stringify(toSend)
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
if (res.status !== 200) {
|
|
158
|
-
throw new Error(`Error while reading data source "${this.name}"`);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
let asJson = await res.json();
|
|
162
|
-
return asJson as JTableDs_ReadResult;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
//endregion
|
|
1
|
+
export * from "./core.ts";
|
|
2
|
+
export * from "./proxy.ts";
|
|
3
|
+
export * from "./interfaces.ts";
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { type Schema } from "jopi-toolkit/jk_schema";
|
|
2
|
+
import type {Translatable} from "../jk_tools";
|
|
3
|
+
|
|
4
|
+
export interface JFieldSorting {
|
|
5
|
+
id: string;
|
|
6
|
+
desc: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface IActionContext {
|
|
10
|
+
refresh: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface JFieldFilter {
|
|
14
|
+
value?: string | number | boolean;
|
|
15
|
+
constraint: JFieldConstraintType;
|
|
16
|
+
caseSensitive?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type JFieldConstraintType =
|
|
20
|
+
| "$eq" // Equals
|
|
21
|
+
| "$ne" // Not equals
|
|
22
|
+
| "$gt" // Greater than
|
|
23
|
+
| "$gte" // Greater than or equals
|
|
24
|
+
| "$lt" // Less than
|
|
25
|
+
| "$lte" // Less than or equals
|
|
26
|
+
| "$in" // In an array of values
|
|
27
|
+
| "$nin" // Not in an array of values
|
|
28
|
+
| "$like" // Like search %endsWith or startsWith%
|
|
29
|
+
;
|
|
30
|
+
|
|
31
|
+
export interface JGlobalFilter {
|
|
32
|
+
field?: string;
|
|
33
|
+
value: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface JPageExtraction {
|
|
37
|
+
pageIndex: number;
|
|
38
|
+
pageSize: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface JRowArrayFilter {
|
|
42
|
+
page?: JPageExtraction;
|
|
43
|
+
filter?: JGlobalFilter;
|
|
44
|
+
sorting?: JFieldSorting[];
|
|
45
|
+
fieldFilters?: Record<string, JFieldFilter[]>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface JDataReadParams extends JRowArrayFilter {
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface JDataReadResult {
|
|
52
|
+
rows: any[];
|
|
53
|
+
total?: number;
|
|
54
|
+
offset?: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface JActionDef {
|
|
58
|
+
id: string;
|
|
59
|
+
title?: Translatable;
|
|
60
|
+
separator?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface JopiDataTable {
|
|
64
|
+
readonly schema: Schema;
|
|
65
|
+
readonly actions?: JActionDef[];
|
|
66
|
+
read(params: JDataReadParams): Promise<JDataReadResult>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface JDataTable extends JopiDataTable {
|
|
70
|
+
readonly name: string;
|
|
71
|
+
executeAction?: (rows: any[], actionName: string, context?: IActionContext) => Promise<JActionResult | void>
|
|
72
|
+
isActionEnabled?: (actionName: string, rows: any[], context?: IActionContext) => boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface JActionPreProcessParams {
|
|
76
|
+
rows: any[];
|
|
77
|
+
context?: IActionContext;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface JActionResult {
|
|
81
|
+
isOk?: boolean;
|
|
82
|
+
errorCode?: string;
|
|
83
|
+
errorMessage?: string;
|
|
84
|
+
userMessage?: string;
|
|
85
|
+
data?: any;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface JActionPreProcessResult extends JActionResult {
|
|
89
|
+
rows?: any[];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface JActionPostProcessParams {
|
|
93
|
+
rows: any[];
|
|
94
|
+
context?: IActionContext;
|
|
95
|
+
|
|
96
|
+
data?: any[];
|
|
97
|
+
userMessage?: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Defines the behavior of a custom action in the browser for a Jopi table.
|
|
102
|
+
* allowing to hook into the action lifecycle (pre-process, server call, post-process).
|
|
103
|
+
*/
|
|
104
|
+
export interface JopiTableBrowserActionItem {
|
|
105
|
+
/**
|
|
106
|
+
* Callback invoked when an error occurs during the action execution.
|
|
107
|
+
* This can be triggered by a failure in the `action` handler or a server-side error.
|
|
108
|
+
*/
|
|
109
|
+
onError?: (params: JActionResult) => Promise<void>,
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The main client-side action handler.
|
|
113
|
+
* - Can be used to perform checks or data transformation before sending to the server.
|
|
114
|
+
* - Can be used as a standalone action if `disableServerCall` is true.
|
|
115
|
+
* - Return `void` to proceed with the default flow.
|
|
116
|
+
* - Return a `JActionPreProcessResult` to control flow (e.g., stop execution if `isOk` is false) or modify data sent to server.
|
|
117
|
+
*/
|
|
118
|
+
action?: (params: JActionPreProcessParams) => Promise<JActionPreProcessResult|void>,
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Callback invoked after the server-side action has successfully completed.
|
|
122
|
+
* Useful for showing notifications, refreshing data, or triggering other UI updates.
|
|
123
|
+
*/
|
|
124
|
+
afterServerCall?: (params: JActionPostProcessParams) => Promise<void>;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Function to determine if the action should be enabled/clickable.
|
|
128
|
+
* Based on the currently selected rows and the current action context.
|
|
129
|
+
* If not provided, the action is assumed to be always enabled.
|
|
130
|
+
*/
|
|
131
|
+
canEnable?: (rows: any[], context?: IActionContext) => boolean;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* If set to true, the framework will NOT assume there is a corresponding server-side action to call.
|
|
135
|
+
* Use this for actions that are purely client-side (e.g., "Copy to clipboard").
|
|
136
|
+
*/
|
|
137
|
+
disableServerCall?: boolean;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export type JopiTableBrowserActions = Record<string, JopiTableBrowserActionItem>
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { IActionContext, JopiTableBrowserActions, JDataReadParams, JDataReadResult, JDataTable, JActionDef, JActionResult } from "./interfaces.ts";
|
|
2
|
+
import { schema, type Schema } from "jopi-toolkit/jk_schema";
|
|
3
|
+
|
|
4
|
+
export interface ProxyParams {
|
|
5
|
+
name: string;
|
|
6
|
+
apiUrl: string;
|
|
7
|
+
actions?: JActionDef[];
|
|
8
|
+
schema: { meta: any; desc: any; };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class Proxy implements JDataTable {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly schema: Schema;
|
|
14
|
+
readonly actions?: JActionDef[];
|
|
15
|
+
private readonly url: string;
|
|
16
|
+
|
|
17
|
+
readonly browserActions: JopiTableBrowserActions;
|
|
18
|
+
|
|
19
|
+
constructor(params: ProxyParams, browserActions: JopiTableBrowserActions) {
|
|
20
|
+
this.name = params.name;
|
|
21
|
+
this.url = params.apiUrl;
|
|
22
|
+
this.actions = params.actions;
|
|
23
|
+
this.schema = schema(params.schema.desc, params.schema.meta);
|
|
24
|
+
this.browserActions = browserActions;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async read(params: JDataReadParams): Promise<JDataReadResult> {
|
|
28
|
+
const asJson = await this.callServer({ dsName: this.name, read: params });
|
|
29
|
+
return asJson as JDataReadResult;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
isActionEnabled(actionName: string, rows: any[], context?: IActionContext): boolean {
|
|
33
|
+
let actionEntry = this.browserActions[actionName];
|
|
34
|
+
if (!actionEntry) return false;
|
|
35
|
+
if (!actionEntry.canEnable) return true;
|
|
36
|
+
return actionEntry.canEnable(rows, context);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async executeAction(rows: any[], actionName: string, context?: IActionContext): Promise<JActionResult|void> {
|
|
40
|
+
async function processError(res: JActionResult | undefined) {
|
|
41
|
+
if (!res) return true;
|
|
42
|
+
|
|
43
|
+
if (res.isOk===false||res.errorCode||res.errorMessage) {
|
|
44
|
+
if (actionEntry.onError) {
|
|
45
|
+
await actionEntry.onError(res);
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let actionEntry = this.browserActions[actionName];
|
|
54
|
+
if (!actionEntry) return;
|
|
55
|
+
|
|
56
|
+
if (actionEntry.action) {
|
|
57
|
+
let res = await actionEntry.action({ rows, context });
|
|
58
|
+
|
|
59
|
+
if (res) {
|
|
60
|
+
if (!processError(res)) return;
|
|
61
|
+
|
|
62
|
+
if (res.rows !== undefined) {
|
|
63
|
+
rows = res.rows;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (actionEntry.disableServerCall === true) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let serverRes = await this.callServer({ action: actionName, rows });
|
|
73
|
+
if (!processError(serverRes)) return;
|
|
74
|
+
|
|
75
|
+
if (actionEntry.afterServerCall) {
|
|
76
|
+
await actionEntry.afterServerCall({
|
|
77
|
+
rows,
|
|
78
|
+
context,
|
|
79
|
+
data: serverRes?.data,
|
|
80
|
+
userMessage: serverRes?.userMessage
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async callServer(data: any): Promise<any> {
|
|
86
|
+
let res = await fetch(this.url, {
|
|
87
|
+
method: "POST",
|
|
88
|
+
headers: {"Content-Type": "application/json"},
|
|
89
|
+
body: JSON.stringify(data)
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (res.status !== 200) {
|
|
93
|
+
throw new Error(`Error while calling data source "${this.name}"`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return await res.json();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function toDataTableProxy(params: ProxyParams, browserActions?: JopiTableBrowserActions): JDataTable {
|
|
101
|
+
return new Proxy(params, browserActions || {});
|
|
102
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculate week-number from a date.
|
|
3
|
+
*/
|
|
4
|
+
export function calcWeekNumber(year: number, month: number, day: number): number {
|
|
5
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
6
|
+
const dayNum = date.getUTCDay() || 7;
|
|
7
|
+
|
|
8
|
+
date.setUTCDate(date.getUTCDate() + (4 - dayNum));
|
|
9
|
+
const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1));
|
|
10
|
+
|
|
11
|
+
return Math.ceil((((date.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
|
|
12
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// noinspection JSUnusedGlobalSymbols
|
|
2
2
|
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
|
-
import fss, {createReadStream
|
|
4
|
+
import fss, {createReadStream} from "node:fs";
|
|
5
5
|
import {fileURLToPath as n_fileURLToPath, pathToFileURL as n_pathToFileURL } from "node:url";
|
|
6
6
|
import {lookup} from "mime-types";
|
|
7
7
|
import {Readable} from "node:stream";
|
|
@@ -172,6 +172,15 @@ export async function writeTextToFile(filePath: string, text: string, createDir:
|
|
|
172
172
|
await fs.writeFile(filePath, text, {encoding: 'utf8', flag: 'w'});
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
export async function appendTextToFile(filePath: string, text: string): Promise<void> {
|
|
176
|
+
try {
|
|
177
|
+
await fs.appendFile(filePath, text, {encoding: 'utf8'});
|
|
178
|
+
} catch {
|
|
179
|
+
await mkDir(path.dirname(filePath));
|
|
180
|
+
await fs.appendFile(filePath, text, {encoding: 'utf8'});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
175
184
|
export function writeTextToFileSync(filePath: string, text: string, createDir: boolean = true): void {
|
|
176
185
|
if (createDir) {
|
|
177
186
|
try {
|
|
@@ -516,6 +525,7 @@ export const join = path.join;
|
|
|
516
525
|
export const resolve = path.resolve;
|
|
517
526
|
export const dirname = path.dirname;
|
|
518
527
|
export const extname = path.extname;
|
|
528
|
+
export const relative = path.relative;
|
|
519
529
|
|
|
520
530
|
export const sep = path.sep;
|
|
521
531
|
export const isAbsolute = path.isAbsolute;
|
package/src/jk_memcache/index.ts
CHANGED
|
@@ -202,18 +202,14 @@ export class JkMemCache {
|
|
|
202
202
|
/**
|
|
203
203
|
* Retrieve an item from the cache with its metadata.
|
|
204
204
|
*/
|
|
205
|
-
public getWithMeta<T = any>(key: string, peek = false): { value: T; meta: any } | null {
|
|
205
|
+
public getWithMeta<T = any>(key: string, peek = false): { value: T; meta: any; size: number } | null {
|
|
206
206
|
const entry = this._storage.get(key);
|
|
207
|
+
|
|
207
208
|
if (!entry) return null;
|
|
208
|
-
|
|
209
|
-
if (entry.expiresAt && entry.expiresAt < Date.now()) {
|
|
210
|
-
this.delete(key);
|
|
211
|
-
return null;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
209
|
if (!peek) entry.accessCount++;
|
|
215
210
|
|
|
216
211
|
let value: T;
|
|
212
|
+
|
|
217
213
|
if (entry.type === 'buffer') {
|
|
218
214
|
value = entry.value as T;
|
|
219
215
|
} else if (entry.type === 'json') {
|
|
@@ -222,7 +218,7 @@ export class JkMemCache {
|
|
|
222
218
|
value = entry.value as T;
|
|
223
219
|
}
|
|
224
220
|
|
|
225
|
-
return { value, meta: entry.meta };
|
|
221
|
+
return { value, meta: entry.meta, size: entry.size };
|
|
226
222
|
}
|
|
227
223
|
|
|
228
224
|
/**
|