@etsoo/materialui 1.3.88 → 1.3.90

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.
@@ -56,16 +56,9 @@ export abstract class CommonApp<
56
56
  * Refresh token
57
57
  * @param props Props
58
58
  */
59
- override async refreshToken<D extends object = Partial<RefreshTokenRQ>>(
60
- props?: RefreshTokenProps<D>
61
- ) {
59
+ override async refreshToken(props?: RefreshTokenProps) {
62
60
  // Destruct
63
- const {
64
- callback,
65
- data,
66
- relogin = false,
67
- showLoading = false
68
- } = props ?? {};
61
+ const { callback, showLoading = false } = props ?? {};
69
62
 
70
63
  // Token
71
64
  const token = this.getCacheToken();
@@ -76,10 +69,7 @@ export abstract class CommonApp<
76
69
 
77
70
  // Reqest data
78
71
  const rq: RefreshTokenRQ = {
79
- deviceId: this.deviceId,
80
- region: this.region,
81
- timezone: this.getTimeZone(),
82
- ...data
72
+ deviceId: this.deviceId
83
73
  };
84
74
 
85
75
  // Login result type
@@ -135,56 +125,9 @@ export abstract class CommonApp<
135
125
  // Remove the wrong token
136
126
  this.clearCacheToken();
137
127
 
138
- if (result.type === "TokenExpired" && relogin) {
139
- // Try login
140
- // Dialog to receive password
141
- var labels = this.getLabels("reloginTip", "login");
142
- this.notifier.prompt(
143
- labels.reloginTip,
144
- async (pwd) => {
145
- if (pwd == null) {
146
- this.toLoginPage();
147
- return;
148
- }
149
-
150
- // Set password for the action
151
- rq.pwd = this.encrypt(this.hash(pwd));
152
-
153
- // Submit again
154
- const result = await this.api.put<LoginResult>(
155
- "Auth/RefreshToken",
156
- rq,
157
- payload
158
- );
159
-
160
- if (result == null) return;
161
-
162
- if (result.ok) {
163
- success(result, (loginResult: RefreshTokenResult) => {
164
- if (loginResult === true) {
165
- if (callback) callback(true);
166
- return;
167
- }
168
-
169
- const message = this.formatRefreshTokenResult(loginResult);
170
- if (message) this.notifier.alert(message);
171
- });
172
- return;
173
- }
174
-
175
- // Popup message
176
- this.alertResult(result);
177
- return false;
178
- },
179
- labels.login,
180
- { type: "password" }
181
- );
182
-
183
- // Fake truth to avoid reloading
184
- return true;
185
- }
186
-
128
+ // Callback
187
129
  if (callback) callback(result);
130
+
188
131
  return false;
189
132
  }
190
133
 
@@ -193,24 +136,18 @@ export abstract class CommonApp<
193
136
 
194
137
  /**
195
138
  * Try login
196
- * @param data Additional data
197
139
  * @param showLoading Show loading bar or not
198
140
  * @returns Result
199
141
  */
200
- override async tryLogin<D extends object = RefreshTokenRQ>(
201
- data?: D,
202
- showLoading?: boolean
203
- ) {
142
+ override async tryLogin(showLoading?: boolean) {
204
143
  // Reset user state
205
- const result = await super.tryLogin(data);
144
+ const result = await super.tryLogin(showLoading);
206
145
  if (!result) return false;
207
146
 
208
147
  // Refresh token
209
148
  return await this.refreshToken({
210
149
  callback: (result) => this.doRefreshTokenResult(result),
211
- data,
212
- showLoading,
213
- relogin: true
150
+ showLoading
214
151
  });
215
152
  }
216
153
  }
@@ -1,36 +1,13 @@
1
- import { IApi, RefreshTokenResult } from "@etsoo/appscript";
2
- import { IServiceUser } from "./IServiceUser";
3
1
  import { ReactAppType } from "./ReactApp";
4
- import { IAppApi } from "./IAppApi";
5
2
 
6
3
  /**
7
4
  * Service application interface
8
5
  */
9
6
  export interface IServiceApp extends ReactAppType {
10
7
  /**
11
- * Service API
8
+ * Load core system UI
12
9
  */
13
- readonly serviceApi: IApi;
14
-
15
- /**
16
- * Service user
17
- */
18
- readonly serviceUser?: IServiceUser;
19
-
20
- /**
21
- * Service application API login
22
- * @param appApi Service application API
23
- * @param callback Callback
24
- */
25
- apiLogin(
26
- appApi: IAppApi,
27
- callback?: (result: RefreshTokenResult, successData?: string) => void
28
- ): Promise<boolean>;
29
-
30
- /**
31
- * Load SmartERP core
32
- */
33
- loadSmartERP(): void;
10
+ loadCore(): void;
34
11
 
35
12
  /**
36
13
  * Service decrypt message
@@ -7,7 +7,7 @@ import { IdType } from "@etsoo/shared";
7
7
  export interface IServiceAppSettings<S extends IdType = number>
8
8
  extends IAppSettings {
9
9
  /**
10
- * Service id
10
+ * Service application id
11
11
  */
12
- readonly serviceId: S;
12
+ readonly appId: S;
13
13
  }
@@ -16,11 +16,6 @@ export interface IServiceUser extends IUser {
16
16
  */
17
17
  readonly organizationName: string;
18
18
 
19
- /**
20
- * Service (App) device id
21
- */
22
- readonly serviceDeviceId: string;
23
-
24
19
  /**
25
20
  * Service (App) passphrase encrypted
26
21
  */
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  BridgeUtils,
3
3
  CoreApp,
4
- createClient,
5
4
  FormatResultCustomCallback,
6
5
  IApp,
7
6
  IAppSettings,
@@ -253,7 +252,7 @@ export class ReactApp<
253
252
  constructor(settings: S, name: string, debug: boolean = false) {
254
253
  super(
255
254
  settings,
256
- createClient(),
255
+ null,
257
256
  ReactApp.createNotifier(debug),
258
257
  new WindowStorage(),
259
258
  name,
@@ -1,29 +1,17 @@
1
1
  import {
2
2
  BridgeUtils,
3
- createClient,
3
+ ExternalEndpoint,
4
4
  IApi,
5
- IApiPayload,
6
- RefreshTokenProps,
7
- RefreshTokenResult,
8
- RefreshTokenRQ
5
+ InitCallDto,
6
+ InitCallResult
9
7
  } from "@etsoo/appscript";
10
- import { CoreConstants } from "@etsoo/react";
11
- import { DomUtils, IActionResult } from "@etsoo/shared";
12
8
  import { IServiceApp } from "./IServiceApp";
13
9
  import { IServiceAppSettings } from "./IServiceAppSettings";
14
10
  import { IServicePageData } from "./IServicePage";
15
- import { IServiceUser, ServiceLoginResult } from "./IServiceUser";
16
- import { ISmartERPUser } from "./ISmartERPUser";
11
+ import { IServiceUser } from "./IServiceUser";
17
12
  import { ReactApp } from "./ReactApp";
18
- import { IAppApi } from "./IAppApi";
19
13
 
20
- /**
21
- * Service application refresh token properties
22
- */
23
- export interface ServiceRefreshTokenProps
24
- extends RefreshTokenProps<Partial<RefreshTokenRQ>> {
25
- appApi?: IAppApi;
26
- }
14
+ const coreName = "core";
27
15
 
28
16
  /**
29
17
  * Core Service App
@@ -36,24 +24,18 @@ export class ServiceApp<
36
24
  P extends IServicePageData = IServicePageData,
37
25
  S extends IServiceAppSettings = IServiceAppSettings
38
26
  >
39
- extends ReactApp<S, ISmartERPUser, P>
27
+ extends ReactApp<S, U, P>
40
28
  implements IServiceApp
41
29
  {
42
30
  /**
43
- * Service API
31
+ * Core endpoint
44
32
  */
45
- readonly serviceApi: IApi;
33
+ protected coreEndpoint: ExternalEndpoint;
46
34
 
47
- private _serviceUser?: U;
48
35
  /**
49
- * Service user
36
+ * Core system API
50
37
  */
51
- get serviceUser() {
52
- return this._serviceUser;
53
- }
54
- protected set serviceUser(value: U | undefined) {
55
- this._serviceUser = value;
56
- }
38
+ readonly coreApi: IApi;
57
39
 
58
40
  /**
59
41
  * Service passphrase
@@ -70,47 +52,37 @@ export class ServiceApp<
70
52
  super(settings, name, debug);
71
53
 
72
54
  // Check
73
- if (settings.serviceId == null || settings.serviceEndpoint == null) {
74
- throw new Error("No service settings");
55
+ if (settings.appId == null) {
56
+ throw new Error("Service Application ID is required.");
75
57
  }
76
58
 
77
- // Service API
78
- const api = createClient();
79
- this.setApi(api);
80
-
81
- // Fix the baseUrl done by setupApi (Default is the settings.endpoint)
82
- api.baseUrl = settings.serviceEndpoint;
59
+ const coreEndpoint = settings.endpoints?.core;
60
+ if (coreEndpoint == null) {
61
+ throw new Error("Core API endpont is required.");
62
+ }
63
+ this.coreEndpoint = coreEndpoint;
83
64
 
84
- this.serviceApi = api;
65
+ this.coreApi = this.createApi(coreName, coreEndpoint);
85
66
  }
86
67
 
87
68
  /**
88
- * Service application API login
89
- * @param appApi Service application API
90
- * @param callback Callback
69
+ * Load core system UI
91
70
  */
92
- apiLogin(
93
- appApi: IAppApi,
94
- callback?: (result: RefreshTokenResult, successData?: string) => void
95
- ) {
96
- return this.refreshToken({
97
- callback,
98
- data: appApi.getRefreshTokenData(),
99
- relogin: false,
100
- showLoading: false,
101
- appApi
102
- });
71
+ loadCore() {
72
+ if (BridgeUtils.host == null) {
73
+ globalThis.location.href = this.coreEndpoint.webUrl;
74
+ } else {
75
+ BridgeUtils.host.loadApp(coreName);
76
+ }
103
77
  }
104
78
 
105
79
  /**
106
- * Load SmartERP core
80
+ * Api init call, for service application, call the core system API
81
+ * @param data Data
82
+ * @returns Result
107
83
  */
108
- loadSmartERP() {
109
- if (BridgeUtils.host == null) {
110
- window.location.href = this.settings.webUrl;
111
- } else {
112
- BridgeUtils.host.loadApp("core");
113
- }
84
+ override async apiInitCall(data: InitCallDto) {
85
+ return await this.coreApi.put<InitCallResult>(this.initCallApi, data);
114
86
  }
115
87
 
116
88
  /**
@@ -119,193 +91,53 @@ export class ServiceApp<
119
91
  * @param removeUrl Remove current URL for reuse
120
92
  */
121
93
  override toLoginPage(tryLogin?: boolean, removeUrl?: boolean) {
122
- const parameters = `?serviceId=${this.settings.serviceId}&${
123
- DomUtils.CultureField
124
- }=${this.culture}${tryLogin ? "" : "&tryLogin=false"}${
125
- removeUrl ? "" : "&url=" + encodeURIComponent(location.href)
126
- }`;
94
+ // Cache current URL
95
+ this.cachedUrl = removeUrl ? undefined : globalThis.location.href;
96
+
127
97
  // Make sure apply new device id for new login
128
98
  this.clearDeviceId();
129
99
 
130
- if (BridgeUtils.host == null) {
131
- const coreUrl = this.settings.webUrl;
132
- window.location.href = coreUrl + parameters;
133
- } else {
134
- BridgeUtils.host.loadApp("core", parameters);
135
- }
100
+ // Get the redirect URL
101
+ this.api
102
+ .get<string>("Auth/GetLogInUrl", {
103
+ region: this.region,
104
+ device: this.deviceId
105
+ })
106
+ .then((url) => {
107
+ if (!url) return;
108
+
109
+ url += `?tryLogin=${tryLogin ?? false}`;
110
+
111
+ if (BridgeUtils.host == null) {
112
+ globalThis.location.href = url;
113
+ } else {
114
+ BridgeUtils.host.loadApp(coreName, url);
115
+ }
116
+ });
136
117
  }
137
118
 
138
119
  /**
139
- * Refresh token
140
- * @param props Props
120
+ * User login extended
121
+ * @param user New user
122
+ * @param refreshToken Refresh token
123
+ * @param keep Keep in local storage or not
124
+ * @param dispatch User state dispatch
141
125
  */
142
- override async refreshToken(props?: ServiceRefreshTokenProps) {
143
- // Destruct
144
- const {
145
- appApi,
146
- callback,
147
- data,
148
- relogin = false,
149
- showLoading = false
150
- } = props ?? {};
151
-
152
- // Token
153
- const token = this.getCacheToken();
154
- if (token == null || token === "") {
155
- if (callback) callback(false);
156
- return false;
157
- }
158
-
159
- // Reqest data
160
- // Merge additional data passed
161
- const rq: RefreshTokenRQ = {
162
- deviceId: this.deviceId,
163
- region: this.region,
164
- timezone: this.getTimeZone(),
165
- ...data
166
- };
167
-
168
- // Login result type
169
- type LoginResult = IActionResult<U>;
170
-
171
- // Payload
172
- const payload: IApiPayload<LoginResult, any> = {
173
- showLoading,
174
- config: { headers: { [CoreConstants.TokenHeaderRefresh]: token } },
175
- onError: (error) => {
176
- if (callback) callback(error);
177
-
178
- // Prevent further processing
179
- return false;
180
- }
181
- };
182
-
183
- // Success callback
184
- const success = async (
185
- result: LoginResult,
186
- failCallback?: (result: RefreshTokenResult) => void
187
- ) => {
188
- // Token
189
- const refreshToken = this.getResponseToken(payload.response);
190
- if (refreshToken == null || result.data == null) {
191
- if (failCallback) failCallback(this.get("noData")!);
192
- return false;
193
- }
194
-
195
- // User data
196
- const userData = result.data;
197
-
198
- // Use core system access token to service api to exchange service access token
199
- const api = appApi ? appApi.api : this.serviceApi;
200
- const serviceResult = await api.put<ServiceLoginResult<U>>(
201
- "Auth/ExchangeToken",
202
- {
203
- token: this.encryptEnhanced(
204
- userData.token,
205
- (appApi?.serviceId ?? this.settings.serviceId).toString()
206
- )
207
- },
208
- {
209
- showLoading,
210
- onError: (error) => {
211
- if (failCallback) failCallback(error);
212
-
213
- // Prevent further processing
214
- return false;
215
- }
216
- }
217
- );
218
-
219
- if (serviceResult == null) return false;
220
-
221
- if (!serviceResult.ok) {
222
- if (failCallback) failCallback(serviceResult);
223
- return false;
224
- }
225
-
226
- if (serviceResult.data == null) {
227
- if (failCallback) failCallback(this.get("noData")!);
228
- return false;
229
- }
230
-
231
- // Login
232
- if (appApi) {
233
- // Authorize external service application API
234
- appApi.authorize(userData, refreshToken, serviceResult.data);
235
- } else {
236
- // Authorize local service
237
- this.userLoginEx(userData, refreshToken, serviceResult.data);
238
- }
239
-
240
- // Success callback
241
- if (failCallback) failCallback(true);
242
-
243
- return true;
244
- };
245
-
246
- // Call API
247
- const result = await this.api.put<LoginResult>(
248
- "Auth/RefreshToken",
249
- rq,
250
- payload
251
- );
252
- if (result == null) return false;
253
-
254
- if (!result.ok) {
255
- if (result.type === "TokenExpired" && relogin) {
256
- // Try login
257
- // Dialog to receive password
258
- var labels = this.getLabels("reloginTip", "login");
259
- this.notifier.prompt(
260
- labels.reloginTip,
261
- async (pwd) => {
262
- if (pwd == null) {
263
- this.toLoginPage();
264
- return;
265
- }
266
-
267
- // Set password for the action
268
- rq.pwd = this.encrypt(this.hash(pwd));
269
-
270
- // Submit again
271
- const result = await this.api.put<LoginResult>(
272
- "Auth/RefreshToken",
273
- rq,
274
- payload
275
- );
276
-
277
- if (result == null) return;
278
-
279
- if (result.ok) {
280
- await success(result, (loginResult: RefreshTokenResult) => {
281
- if (loginResult === true) {
282
- if (callback) callback(true);
283
- return;
284
- }
285
-
286
- const message = this.formatRefreshTokenResult(loginResult);
287
- if (message) this.notifier.alert(message);
288
- });
289
- return;
290
- }
291
-
292
- // Popup message
293
- this.alertResult(result);
294
- return false;
295
- },
296
- labels.login,
297
- { type: "password" }
298
- );
299
-
300
- // Fake truth to avoid reloading
301
- return true;
302
- }
303
-
304
- if (callback) callback(result);
305
- return false;
306
- }
307
-
308
- return await success(result, callback);
126
+ override userLogin(
127
+ user: U,
128
+ refreshToken: string,
129
+ keep?: boolean,
130
+ dispatch?: boolean
131
+ ): void {
132
+ // Super call, set token
133
+ super.userLogin(user, refreshToken, keep, dispatch);
134
+
135
+ // Set service passphrase
136
+ this.servicePassphrase =
137
+ this.decrypt(
138
+ user.servicePassphrase,
139
+ `${user.uid}-${this.settings.appId}`
140
+ ) ?? "";
309
141
  }
310
142
 
311
143
  /**
@@ -332,55 +164,4 @@ export class ServiceApp<
332
164
  iterations
333
165
  );
334
166
  }
335
-
336
- /**
337
- * Try login
338
- * @param data Additional data
339
- * @param showLoading Show loading bar or not
340
- * @returns Result
341
- */
342
- override async tryLogin<D extends object = {}>(
343
- data?: D,
344
- showLoading?: boolean
345
- ) {
346
- // Reset user state
347
- const result = await super.tryLogin(data, showLoading);
348
- if (!result) return false;
349
-
350
- // Refresh token
351
- return await this.refreshToken({
352
- callback: (result) => this.doRefreshTokenResult(result),
353
- data,
354
- showLoading,
355
- relogin: true
356
- });
357
- }
358
-
359
- /**
360
- * User login extended
361
- * @param user Core system user
362
- * @param refreshToken Refresh token
363
- * @param serviceUser Service user
364
- */
365
- userLoginEx(user: ISmartERPUser, refreshToken: string, serviceUser: U) {
366
- // Service user login
367
- this.servicePassphrase =
368
- this.decrypt(
369
- serviceUser.servicePassphrase,
370
- this.settings.serviceId.toString()
371
- ) ?? "";
372
-
373
- // Service user
374
- this.serviceUser = serviceUser;
375
-
376
- // Service API token
377
- this.serviceApi.authorize(
378
- serviceUser.tokenScheme ?? "Bearer",
379
- serviceUser.token
380
- );
381
-
382
- // Keep = true, means service could hold the refresh token for long access
383
- // Trigger Context change and serviceUser is ready then
384
- super.userLogin(user, refreshToken, true);
385
- }
386
167
  }
package/src/index.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from "./app/CommonApp";
2
- export * from "./app/IAppApi";
3
2
  export * from "./app/IServiceApp";
4
3
  export * from "./app/IServiceAppSettings";
5
4
  export * from "./app/IServicePage";
@@ -1,29 +0,0 @@
1
- import { IApi } from "@etsoo/restclient";
2
- import { ISmartERPUser } from "./ISmartERPUser";
3
- import { RefreshTokenRQ } from "@etsoo/appscript";
4
- import { IServiceUser } from "./IServiceUser";
5
- /**
6
- * Service application API, Implement interface calls between different services
7
- * 服务程序接口,实现不同服务之间的接口调用
8
- */
9
- export interface IAppApi {
10
- /**
11
- * API
12
- */
13
- readonly api: IApi<any>;
14
- /**
15
- * Service id
16
- */
17
- readonly serviceId: number;
18
- /**
19
- * Authorize the API
20
- * @param user SmartERP user
21
- * @param refreshToken SmartERP user refresh token
22
- * @param serviceUser Service user
23
- */
24
- authorize(user: ISmartERPUser, refreshToken: string, serviceUser: IServiceUser): void;
25
- /**
26
- * Get refresh token data
27
- */
28
- getRefreshTokenData(): Partial<RefreshTokenRQ>;
29
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,37 +0,0 @@
1
- import { IApi } from "@etsoo/restclient";
2
- import { ISmartERPUser } from "./ISmartERPUser";
3
- import { RefreshTokenRQ } from "@etsoo/appscript";
4
- import { IServiceUser } from "./IServiceUser";
5
-
6
- /**
7
- * Service application API, Implement interface calls between different services
8
- * 服务程序接口,实现不同服务之间的接口调用
9
- */
10
- export interface IAppApi {
11
- /**
12
- * API
13
- */
14
- readonly api: IApi<any>;
15
-
16
- /**
17
- * Service id
18
- */
19
- readonly serviceId: number;
20
-
21
- /**
22
- * Authorize the API
23
- * @param user SmartERP user
24
- * @param refreshToken SmartERP user refresh token
25
- * @param serviceUser Service user
26
- */
27
- authorize(
28
- user: ISmartERPUser,
29
- refreshToken: string,
30
- serviceUser: IServiceUser
31
- ): void;
32
-
33
- /**
34
- * Get refresh token data
35
- */
36
- getRefreshTokenData(): Partial<RefreshTokenRQ>;
37
- }