zavadil-ts-common 1.0.0

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.
Files changed (52) hide show
  1. package/.env-example +1 -0
  2. package/README.MD +16 -0
  3. package/bin/build +2 -0
  4. package/bin/build.cmd +2 -0
  5. package/bin/install +1 -0
  6. package/bin/install.cmd +1 -0
  7. package/bin/publish +2 -0
  8. package/bin/publish.cmd +2 -0
  9. package/dist/component/CancellablePromise.d.ts +11 -0
  10. package/dist/component/EventManager.d.ts +12 -0
  11. package/dist/component/OAuthRestClient.d.ts +58 -0
  12. package/dist/component/OAuthSessionManager.d.ts +23 -0
  13. package/dist/component/OAuthSubject.d.ts +7 -0
  14. package/dist/component/RestClient.d.ts +24 -0
  15. package/dist/component/UserAlerts.d.ts +19 -0
  16. package/dist/component/index.d.ts +7 -0
  17. package/dist/index.d.ts +215 -0
  18. package/dist/index.esm.js +2 -0
  19. package/dist/index.esm.js.map +1 -0
  20. package/dist/index.js +2 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/type/Paging.d.ts +17 -0
  23. package/dist/type/UserAlert.d.ts +6 -0
  24. package/dist/type/index.d.ts +2 -0
  25. package/dist/util/ArrayUtil.d.ts +5 -0
  26. package/dist/util/AsyncUtil.d.ts +3 -0
  27. package/dist/util/ByteUtil.d.ts +3 -0
  28. package/dist/util/ObjectUtil.d.ts +5 -0
  29. package/dist/util/StringUtil.d.ts +14 -0
  30. package/dist/util/index.d.ts +5 -0
  31. package/docker-compose.yml +24 -0
  32. package/package.json +26 -0
  33. package/rollup.config.mjs +41 -0
  34. package/src/component/CancellablePromise.ts +38 -0
  35. package/src/component/EventManager.ts +30 -0
  36. package/src/component/OAuthRestClient.ts +92 -0
  37. package/src/component/OAuthSessionManager.ts +143 -0
  38. package/src/component/OAuthSubject.ts +25 -0
  39. package/src/component/RestClient.ts +153 -0
  40. package/src/component/UserAlerts.ts +73 -0
  41. package/src/component/index.ts +7 -0
  42. package/src/index.ts +3 -0
  43. package/src/type/Paging.ts +21 -0
  44. package/src/type/UserAlert.ts +6 -0
  45. package/src/type/index.ts +3 -0
  46. package/src/util/ArrayUtil.ts +20 -0
  47. package/src/util/AsyncUtil.ts +3 -0
  48. package/src/util/ByteUtil.ts +11 -0
  49. package/src/util/ObjectUtil.ts +21 -0
  50. package/src/util/StringUtil.ts +65 -0
  51. package/src/util/index.ts +5 -0
  52. package/tsconfig.json +29 -0
@@ -0,0 +1,153 @@
1
+ import { StringUtil } from "../util";
2
+ import {PagingRequest, SortingField, SortingRequest} from "../type";
3
+
4
+ export type RestClientHeaders = {};
5
+
6
+ export class RestClient {
7
+
8
+ private baseUrl: string;
9
+
10
+ constructor(baseUrl: string) {
11
+ this.baseUrl = baseUrl;
12
+ }
13
+
14
+ static sortingFieldToString(s: SortingField): string | undefined {
15
+ return s.desc ? `${s.name} DESC` : s.name;
16
+ }
17
+
18
+ static sortingRequestToString(s: SortingRequest): string | undefined {
19
+ return s.map((s: SortingField) => RestClient.sortingFieldToString(s)).join(',');
20
+ }
21
+
22
+ static pagingRequestToQueryParams(pr: PagingRequest): any {
23
+ const result: any = {
24
+ page: pr.page,
25
+ size: pr.size
26
+ }
27
+ if (pr.search) {
28
+ result.search = pr.search;
29
+ }
30
+ if (pr.sorting) {
31
+ result.sorting = RestClient.sortingRequestToString(pr.sorting);
32
+ }
33
+ return result;
34
+ }
35
+
36
+ /**
37
+ * Override this to customize http headers.
38
+ */
39
+ getHeaders(): Promise<RestClientHeaders> {
40
+ return Promise.resolve(
41
+ {
42
+ 'Content-Type': 'application/json'
43
+ }
44
+ );
45
+ }
46
+
47
+ getUrl(endpoint: string) {
48
+ return [StringUtil.trimSlashes(this.baseUrl), StringUtil.trimSlashes(endpoint)].join('/');
49
+ }
50
+
51
+ getRequestOptions(method: string = 'GET', data: object | null = null): Promise<any> {
52
+ return this.getHeaders()
53
+ .then(
54
+ (headers) => {
55
+ return {
56
+ method: method,
57
+ headers: headers,
58
+ body: data === null ? null : JSON.stringify(data)
59
+ };
60
+ }
61
+ );
62
+ }
63
+
64
+ processRequest(endpoint: string, requestOptions?: object): Promise<Response> {
65
+ return fetch(this.getUrl(endpoint), requestOptions)
66
+ .then((response) => {
67
+ if (!response.ok) {
68
+ const options = {cause: response.status};
69
+ if (response.headers.get('Content-Type') === 'application/json') {
70
+ return response
71
+ .json()
72
+ .then((json) => {
73
+ if (json.message) {
74
+ // @ts-ignore
75
+ throw new Error(json.message, options);
76
+ }
77
+ if (json.error) {
78
+ // @ts-ignore
79
+ throw new Error(json.error, options);
80
+ }
81
+ // @ts-ignore
82
+ throw new Error(response.statusText, options);
83
+ }, () => {
84
+ // @ts-ignore
85
+ throw new Error(response.statusText, options);
86
+ });
87
+ } else {
88
+ return response.text().then(
89
+ (t) => {
90
+ if (StringUtil.isEmpty(t)) {
91
+ // @ts-ignore
92
+ throw new Error(response.statusText, options);
93
+ } else {
94
+ // @ts-ignore
95
+ throw new Error(t, options);
96
+ }
97
+ },
98
+ () => {
99
+ // @ts-ignore
100
+ throw new Error(response.statusText, options);
101
+ }
102
+ );
103
+ }
104
+ }
105
+ return response;
106
+ });
107
+ }
108
+
109
+ processRequestJson(url: string, requestOptions?: object | undefined): Promise<any> {
110
+ return this.processRequest(url, requestOptions)
111
+ .then((response) => {
112
+ return response.json();
113
+ });
114
+ }
115
+
116
+ getJson(url: string, params?: any): Promise<any> {
117
+ if (params) {
118
+ const original = new URLSearchParams(params);
119
+ const cleaned = new URLSearchParams();
120
+ original.forEach((value, key) => {
121
+ if (value !== '' && value !== undefined && value !== "undefined")
122
+ cleaned.set(key, value);
123
+ });
124
+ url = `${url}?${cleaned.toString()}`;
125
+ }
126
+ return this.getRequestOptions().then(o => this.processRequestJson(url, o));
127
+ }
128
+
129
+ postJson(url: string, data: object | null = null): Promise<any> {
130
+ return this.getRequestOptions('POST', data).then(o => this.processRequestJson(url, o));
131
+ }
132
+
133
+ putJson(url: string, data: object | null = null): Promise<any> {
134
+ return this.getRequestOptions('PUT', data).then(o => this.processRequestJson(url, o));
135
+ }
136
+
137
+ get(url: string): Promise<Response> {
138
+ return this.getRequestOptions().then(o => this.processRequest(url, o));
139
+ }
140
+
141
+ del(url: string): Promise<Response> {
142
+ return this.getRequestOptions('DELETE').then(o => this.processRequest(url, o));
143
+ }
144
+
145
+ post(url: string, data: object | null = null): Promise<Response> {
146
+ return this.getRequestOptions('POST', data).then(o => this.processRequest(url, o));
147
+ }
148
+
149
+ put(url: string, data: object | null = null): Promise<Response> {
150
+ return this.getRequestOptions('PUT', data).then(o => this.processRequest(url, o));
151
+ }
152
+
153
+ }
@@ -0,0 +1,73 @@
1
+ import {UserAlert} from "../type";
2
+ import {EventManager, Func} from "./EventManager";
3
+
4
+ export class UserAlerts {
5
+
6
+ private lifetimeMs: number = 10000;
7
+
8
+ private em: EventManager;
9
+
10
+ public alerts: Array<UserAlert>;
11
+
12
+ constructor() {
13
+ this.em = new EventManager();
14
+ this.alerts = [];
15
+ setInterval(() => this.flushAlerts(), 1000)
16
+ }
17
+
18
+ flushAlerts() {
19
+ const now = new Date();
20
+ const threshold = now.getTime() - this.lifetimeMs;
21
+ this.alerts = this.alerts.filter((a) => a.time.getTime() > threshold);
22
+ this.triggerChange();
23
+ }
24
+
25
+ addOnChangeHandler(h: Func) {
26
+ this.em.addEventListener('change', h);
27
+ }
28
+
29
+ removeOnChangeHandler(h: Func) {
30
+ this.em.removeEventListener('change', h);
31
+ }
32
+
33
+ triggerChange() {
34
+ this.em.triggerEvent('change');
35
+ }
36
+
37
+ reset() {
38
+ this.alerts = [];
39
+ this.triggerChange();
40
+ }
41
+
42
+ remove(alert: UserAlert) {
43
+ this.alerts.splice(this.alerts.indexOf(alert), 1);
44
+ this.triggerChange();
45
+ };
46
+
47
+ add(alert: UserAlert) {
48
+ this.alerts.push(alert);
49
+ this.triggerChange();
50
+ }
51
+
52
+ custom(type: string, title: string, message: string) {
53
+ this.add({
54
+ time: new Date(),
55
+ type: type,
56
+ title: title,
57
+ message: message
58
+ });
59
+ }
60
+
61
+ err(message: string) {
62
+ this.custom('danger', 'Error', message);
63
+ }
64
+
65
+ warn(message: string) {
66
+ this.custom('warning', 'Warning', message);
67
+ }
68
+
69
+ info(message: string) {
70
+ this.custom('info', 'Warning', message);
71
+ }
72
+
73
+ }
@@ -0,0 +1,7 @@
1
+ export * from './EventManager';
2
+ export * from './UserAlerts';
3
+ export * from './RestClient';
4
+ export * from './OAuthRestClient';
5
+ export * from './OAuthSessionManager';
6
+ export * from './OAuthSubject';
7
+ export * from './CancellablePromise';
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './type';
2
+ export * from './util';
3
+ export * from './component';
@@ -0,0 +1,21 @@
1
+ export type SortingField = {
2
+ name: string;
3
+ desc?: boolean;
4
+ };
5
+
6
+ export type SortingRequest = Array<SortingField>;
7
+
8
+ export type PagingRequest = {
9
+ page: number;
10
+ size: number;
11
+ search?: string | null;
12
+ sorting: SortingRequest;
13
+ };
14
+
15
+ export type Page<Type> = {
16
+ totalPages: number;
17
+ totalElements: number;
18
+ number: number;
19
+ content: Array<Type>;
20
+ };
21
+
@@ -0,0 +1,6 @@
1
+ export type UserAlert = {
2
+ time: Date;
3
+ type: string;
4
+ title?: string;
5
+ message: string;
6
+ }
@@ -0,0 +1,3 @@
1
+ export * from './Paging';
2
+ export * from './UserAlert';
3
+
@@ -0,0 +1,20 @@
1
+ import { ObjectUtil } from "./ObjectUtil";
2
+
3
+ export class ArrayUtil {
4
+
5
+ static isEmpty(arr?: Array<any> | null): boolean {
6
+ // @ts-ignore
7
+ return ObjectUtil.isEmpty(arr) || arr.length === 0;
8
+ }
9
+
10
+ static notEmpty(arr?: Array<any> | null): boolean {
11
+ return !ArrayUtil.isEmpty(arr);
12
+ }
13
+
14
+ static remove(arr?: Array<any> | null, element?: any): Array<any> {
15
+ if (ArrayUtil.isEmpty(arr)) return [];
16
+ // @ts-ignore
17
+ return arr?.filter(e => e !== element);
18
+ }
19
+
20
+ }
@@ -0,0 +1,3 @@
1
+ export class AsyncUtil {
2
+ static sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
3
+ }
@@ -0,0 +1,11 @@
1
+ export class ByteUtil {
2
+
3
+ static formatByteSize(size?: number | null): string {
4
+ const n = Number(size);
5
+ if (n === null || Number.isNaN(n)) return '';
6
+ if (n === 0) return '0';
7
+ const l = Math.floor(Math.log(n) / Math.log(1024));
8
+ return +((n / Math.pow(1024, l)).toFixed(2)) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][l];
9
+ }
10
+
11
+ }
@@ -0,0 +1,21 @@
1
+ export class ObjectUtil {
2
+
3
+ static isEmpty(obj: any) {
4
+ return obj === undefined || obj === null;
5
+ }
6
+
7
+ static notEmpty(obj: any) {
8
+ return !ObjectUtil.isEmpty(obj);
9
+ }
10
+
11
+ static clone<T>(obj: T): T {
12
+ if (obj === null) {
13
+ throw new Error("Null cannot be cloned!");
14
+ }
15
+ if (typeof obj !== 'object') {
16
+ throw new Error("Not an object, cannot be cloned!");
17
+ }
18
+ return {...obj};
19
+ }
20
+
21
+ }
@@ -0,0 +1,65 @@
1
+ import { ObjectUtil } from "./ObjectUtil";
2
+
3
+ export class StringUtil extends ObjectUtil {
4
+
5
+ static isEmpty(str: string | null | undefined): boolean {
6
+ return ObjectUtil.isEmpty(str) || str?.trim().length === 0;
7
+ }
8
+
9
+ static notEmpty(str: string | null | undefined): boolean {
10
+ return !StringUtil.isEmpty(str);
11
+ }
12
+
13
+ static substr(str: string | null | undefined, start: number, length?: number): string {
14
+ if (this.isEmpty(str)) return '';
15
+
16
+ // @ts-ignore
17
+ return str.substring(start, length);
18
+ }
19
+
20
+ static replace(str: string | null | undefined, find?: null | string, replace?: string): string {
21
+ if (this.isEmpty(str) || this.isEmpty(find)) return '';
22
+
23
+ // @ts-ignore
24
+ return str.replace(find, String(replace));
25
+ }
26
+
27
+ static containsLineBreaks(str: string | null | undefined): boolean {
28
+ if (str === null || str === undefined || str.trim().length === 0) return false;
29
+ return str.includes("\n");
30
+ }
31
+
32
+ static trimSlashes(str: string | null): string {
33
+ if (this.isEmpty(str)) return '';
34
+
35
+ // @ts-ignore
36
+ return str.replace(/^\/|\/$/g, '');
37
+ }
38
+
39
+ static safeTruncate(str: string | null | undefined, len: number, ellipsis: string = ''): string {
40
+ if (StringUtil.isEmpty(str) || !str) return '';
41
+ if (str.length <= len) return String(str);
42
+ return str.substring(0, len - ellipsis.length) + ellipsis;
43
+ }
44
+
45
+ static ellipsis(str: string | null | undefined, len: number, ellipsis: string = '...'): string {
46
+ return StringUtil.safeTruncate(str, len, ellipsis);
47
+ }
48
+
49
+ static safeTrim(str: string | null | undefined): string {
50
+ if (StringUtil.isEmpty(str) || !str) return '';
51
+ return str.trim();
52
+ }
53
+
54
+ static toBigInt(str: string | null): bigint | null {
55
+ if (this.isEmpty(str)) return null;
56
+
57
+ // @ts-ignore
58
+ return BigInt(str);
59
+ }
60
+
61
+ static getNonEmpty(...args: Array<string | null | undefined>): string {
62
+ return args.find(a => StringUtil.notEmpty(a)) || "";
63
+ }
64
+
65
+ }
@@ -0,0 +1,5 @@
1
+ export { ObjectUtil } from './ObjectUtil';
2
+ export { StringUtil } from './StringUtil';
3
+ export { ArrayUtil } from './ArrayUtil';
4
+ export { AsyncUtil } from './AsyncUtil';
5
+ export { ByteUtil } from './ByteUtil';
package/tsconfig.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "compilerOptions": {
3
+ "moduleResolution": "node",
4
+ "target": "es5",
5
+ "module": "ESNext",
6
+ "lib": [
7
+ "es6",
8
+ "dom",
9
+ "es2020.bigint"
10
+ ],
11
+ "outDir": "./dist",
12
+ "rootDir": "./src",
13
+ "declaration": true,
14
+ "strict": true,
15
+ "esModuleInterop": true,
16
+ "skipLibCheck": true
17
+ },
18
+ "include": [
19
+ "src",
20
+ "*.tsx",
21
+ "*.ts"
22
+ ],
23
+ "exclude": [
24
+ "node_modules/**",
25
+ "dist",
26
+ "docker-compose.yml",
27
+ ".env-example"
28
+ ]
29
+ }