procode-lowcode-core 1.0.16 → 1.0.18

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 (30) hide show
  1. package/dist/index.esm.js +212 -109
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/index.js +212 -109
  4. package/dist/index.js.map +1 -1
  5. package/dist/types/Action/helpers/hasFieldValidationErrors.d.ts +2 -0
  6. package/dist/types/ApplicationStart/AppDependenceyProvider.d.ts +4 -1
  7. package/dist/types/ApplicationStart/HOC/FieldValidationDispatcher.d.ts +9 -0
  8. package/dist/types/Constant.d.ts +1 -0
  9. package/dist/types/DataModel/CoreViewModelHandler.d.ts +2 -0
  10. package/dist/types/DataModel/SupportiveFunctions/index.d.ts +2 -2
  11. package/dist/types/Services/CentralService.d.ts +1 -1
  12. package/dist/types/Services/helpers/defaultFieldErrorMapper.d.ts +4 -0
  13. package/dist/types/Validation/IValidationFactory.d.ts +2 -1
  14. package/dist/types/Validation/StandardValidations/StandardValidationFactory.d.ts +3 -0
  15. package/dist/types/Validation/StandardValidations/alphanumericSpaceValidation.d.ts +5 -0
  16. package/package.json +1 -1
  17. package/src/Action/StandardActions/handleCreateAndNavigate.ts +16 -11
  18. package/src/Action/StandardActions/handleUpdateAndNavigate.ts +16 -11
  19. package/src/Action/helpers/hasFieldValidationErrors.ts +16 -0
  20. package/src/ApplicationStart/AppDependenceyProvider.ts +13 -0
  21. package/src/ApplicationStart/HOC/FieldValidationDispatcher.ts +21 -0
  22. package/src/ApplicationStart/helper/setupStoreAction.ts +12 -1
  23. package/src/Constant.ts +1 -0
  24. package/src/DataModel/CoreViewModelHandler.ts +221 -241
  25. package/src/DataModel/SupportiveFunctions/index.ts +12 -8
  26. package/src/Services/CentralService.ts +66 -57
  27. package/src/Services/helpers/defaultFieldErrorMapper.ts +40 -0
  28. package/src/Validation/IValidationFactory.ts +1 -0
  29. package/src/Validation/StandardValidations/StandardValidationFactory.ts +2 -0
  30. package/src/Validation/StandardValidations/alphanumericSpaceValidation.ts +20 -0
@@ -0,0 +1,2 @@
1
+ import { EventService } from "../../Services/EventService";
2
+ export declare const hasFieldValidationErrors: (eventService: EventService | undefined) => boolean;
@@ -1,6 +1,7 @@
1
1
  import IAdapterProvider from "../Adapter/IAdapterProvider";
2
2
  import { IViewModelHandler } from "../DataModel/IViewModelHandler";
3
3
  import { ResponseFormat } from "../Services/helpers/coreResponseFormatter";
4
+ import { FieldErrorMapper } from "../Services/helpers/defaultFieldErrorMapper";
4
5
  export declare class AppDependenceyProvider {
5
6
  private _adapterProvider?;
6
7
  private _viewModelHandler?;
@@ -10,9 +11,10 @@ export declare class AppDependenceyProvider {
10
11
  private _requestHeaders?;
11
12
  private _getSchemaBySlugService?;
12
13
  private _responseFormatter?;
14
+ private _fieldErrorMapper?;
13
15
  private static instance;
14
16
  private constructor();
15
- static initInstance: ({ adapterProvider, viewModelHandler, widgetProvider, templateWidgetProvider, customWidgetProvider, requestHeaders, getSchemaBySlugService, responseFormatter, }: any) => void;
17
+ static initInstance: ({ adapterProvider, viewModelHandler, widgetProvider, templateWidgetProvider, customWidgetProvider, requestHeaders, getSchemaBySlugService, responseFormatter, fieldErrorMapper, }: any) => void;
16
18
  static getInstance: () => AppDependenceyProvider;
17
19
  getAdapterProvider: () => IAdapterProvider;
18
20
  getViewModelHandler: () => IViewModelHandler;
@@ -22,4 +24,5 @@ export declare class AppDependenceyProvider {
22
24
  getRequestHeaders: () => any;
23
25
  getSchemaBySlugService: () => any;
24
26
  getResponseFormatter: () => (data: any, status: number) => ResponseFormat;
27
+ getFieldErrorMapper: () => FieldErrorMapper;
25
28
  }
@@ -0,0 +1,9 @@
1
+ type FieldErrors = Record<string, string[]>;
2
+ type Handler = (errors: FieldErrors) => void;
3
+ declare class FieldValidationDispatcher {
4
+ private static handler?;
5
+ static registerHandler(handler: Handler): void;
6
+ static dispatch(errors: FieldErrors): void;
7
+ }
8
+ export default FieldValidationDispatcher;
9
+ export type { FieldErrors };
@@ -6,6 +6,7 @@ export declare const eventServiceType: {
6
6
  UI_SCHEMA_ACTION: string;
7
7
  UISCHEMA: string;
8
8
  DATASTATE: string;
9
+ APP_STATE: string;
9
10
  REQUEST_START: string;
10
11
  REQUEST_END: string;
11
12
  };
@@ -6,6 +6,8 @@ export declare class CoreViewModelHandler implements IViewModelHandler {
6
6
  private static instance;
7
7
  private static createInstance;
8
8
  static getInstance(): CoreViewModelHandler;
9
+ private applyBefore;
10
+ private resolveAfter;
9
11
  getViewModel: (screenDataQueryParams: QueryFilters, supportiveQueryParams: string[], apiConfig: ApiConfig, eventService: EventService) => Promise<ViewModel>;
10
12
  getModel: (screenDataQueryParams: QueryFilters, apiConfig: ApiConfig, eventService: EventService) => Promise<any>;
11
13
  getSupportiveData: (supportiveQueryParams: string[], apiConfig: ApiConfig, eventService: EventService) => Promise<any>;
@@ -7,6 +7,6 @@ export declare const deserializedSupportiveData: (eventService: EventService, su
7
7
  export declare const serializedSupportiveQueryParams: (eventService: EventService, supportiveQueryParams: any) => any;
8
8
  export declare const serializedScreenDataQueryParams: (eventService: EventService, screenDataQueryParams: QueryFilters) => any;
9
9
  export declare const serializedModel: (eventService: EventService, model: any) => any;
10
- export declare const fetchDataAndDeserialize: (queryParam: string, apiConfig: ApiConfig, eventService: EventService, fetchService: (apiConfig: ApiConfig, queryParam: string, eventService: EventService) => Promise<ServicesResponse>, deserializeFn: (eventService: EventService, servicesResponse: ServicesResponse) => any) => Promise<any>;
10
+ export declare const fetchDataAndDeserialize: (queryParam: string, apiConfig: ApiConfig, eventService: EventService, fetchService: (apiConfig: ApiConfig, queryParam: string, eventService: EventService) => Promise<ServicesResponse>, deserializeFn: ((eventService: EventService, servicesResponse: ServicesResponse) => any) | null) => Promise<any>;
11
11
  export declare const handleRequest: (requestFn: () => Promise<any>, eventService: EventService) => Promise<any>;
12
- export declare const handleFetchRequest: (queryParam: string, apiConfig: ApiConfig, eventService: EventService, fetchService: (apiConfig: ApiConfig, queryParam: string, eventService: EventService) => Promise<ServicesResponse>, deserializeFn: (eventService: EventService, servicesResponse: ServicesResponse) => any) => Promise<any>;
12
+ export declare const handleFetchRequest: (queryParam: string, apiConfig: ApiConfig, eventService: EventService, fetchService: (apiConfig: ApiConfig, queryParam: string, eventService: EventService) => Promise<ServicesResponse>, deserializeFn: ((eventService: EventService, servicesResponse: ServicesResponse) => any) | null) => Promise<any>;
@@ -15,5 +15,5 @@ export declare class CentralService {
15
15
  private setInterceptorsRequest;
16
16
  private static initInstance;
17
17
  static getInstance(): CentralService;
18
- getAxioInstance: () => AxiosInstance | null;
18
+ getAxioInstance: () => AxiosInstance;
19
19
  }
@@ -0,0 +1,4 @@
1
+ import { FieldErrors } from "../../ApplicationStart/HOC/FieldValidationDispatcher";
2
+ export type FieldErrorMapper = (raw: unknown) => FieldErrors;
3
+ declare const defaultFieldErrorMapper: FieldErrorMapper;
4
+ export default defaultFieldErrorMapper;
@@ -9,7 +9,8 @@ export declare enum StandardValidationType {
9
9
  LESS_THAN = "LESS_THAN",
10
10
  LESS_THAN_EQUAL = "LESS_THAN_EQUAL",
11
11
  BETWEEN = "BETWEEN",
12
- NOT_BETWEEN = "NOT_BETWEEN"
12
+ NOT_BETWEEN = "NOT_BETWEEN",
13
+ ALPHANUMERIC_SPACE = "ALPHANUMERIC_SPACE"
13
14
  }
14
15
  export type ValidationFcResponse = {
15
16
  isValid: boolean;
@@ -34,6 +34,9 @@ declare class StandardValidationFactory implements IValidationFactory {
34
34
  }) | (({ validation, viewModel, value, }: import("../Types").ValidationFcProperties) => {
35
35
  isValid: boolean;
36
36
  message: string;
37
+ }) | (({ validation, value, }: import("../Types").ValidationFcProperties) => {
38
+ isValid: boolean;
39
+ message: string;
37
40
  });
38
41
  }
39
42
  export default StandardValidationFactory;
@@ -0,0 +1,5 @@
1
+ import { ValidationFcProperties } from "../Types";
2
+ export declare const alphanumericSpaceValidation: ({ validation, value, }: ValidationFcProperties) => {
3
+ isValid: boolean;
4
+ message: string;
5
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "procode-lowcode-core",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "ProCode Core Library - React framework for low-code applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -5,13 +5,13 @@ import { validateUiElementSchema } from "../helpers/validateUiElementSchema";
5
5
  import { ActionInvokerProperties } from "../Types";
6
6
  import handleNavigation from "./handleNavigation";
7
7
  import { appActions } from "../../Store/Slices/appSlice";
8
+ import { hasFieldValidationErrors } from "../helpers/hasFieldValidationErrors";
8
9
 
9
10
  const handleCreateAndNavigate = async (
10
11
  actionInvokerProps: ActionInvokerProperties,
11
12
  ) => {
12
13
  const eventService = actionInvokerProps.eventService;
13
14
  const dispatch = eventService?.emit(eventServiceType.DISPATCH_STORE);
14
- // const appActions = eventService?.emit(eventServiceType.DATASTATE_ACTION);
15
15
  const uiSchema = eventService?.emit(eventServiceType.UISCHEMA);
16
16
 
17
17
  const apiConfig =
@@ -38,16 +38,21 @@ const handleCreateAndNavigate = async (
38
38
  appActions?.loadValidation(validationResult.schemaInvalidMessages),
39
39
  );
40
40
 
41
- if (validationResult.isSchemaValid) {
42
- await AppDependenceyProvider.getInstance()
43
- .getViewModelHandler()
44
- ?.createModel(
45
- actionInvokerProps.viewModel.screenData,
46
- apiConfig,
47
- eventService,
48
- );
41
+ if (!validationResult.isSchemaValid) return;
49
42
 
50
- handleNavigation(actionInvokerProps);
51
- }
43
+ await AppDependenceyProvider.getInstance()
44
+ .getViewModelHandler()
45
+ ?.createModel(
46
+ actionInvokerProps.viewModel.screenData,
47
+ apiConfig,
48
+ eventService,
49
+ );
50
+
51
+ // The response interceptor pushes server-side field errors into
52
+ // state.validation via FieldValidationDispatcher. Don't navigate away
53
+ // from a form the user still has to fix.
54
+ if (hasFieldValidationErrors(eventService)) return;
55
+
56
+ handleNavigation(actionInvokerProps);
52
57
  };
53
58
  export default handleCreateAndNavigate;
@@ -5,13 +5,13 @@ import { validateUiElementSchema } from "../helpers/validateUiElementSchema";
5
5
  import { ActionInvokerProperties } from "../Types";
6
6
  import handleNavigation from "./handleNavigation";
7
7
  import { appActions } from "../../Store/Slices/appSlice";
8
+ import { hasFieldValidationErrors } from "../helpers/hasFieldValidationErrors";
8
9
 
9
10
  const handleUpdateAndNavigate = async (
10
11
  actionInvokerProps: ActionInvokerProperties
11
12
  ) => {
12
13
  const eventService = actionInvokerProps.eventService;
13
14
  const dispatch = eventService?.emit(eventServiceType.DISPATCH_STORE);
14
- // const appActions = eventService?.emit(eventServiceType.DATASTATE_ACTION);
15
15
  const uiSchema = eventService?.emit(eventServiceType.UISCHEMA);
16
16
 
17
17
  const apiConfig =
@@ -38,16 +38,21 @@ const handleUpdateAndNavigate = async (
38
38
  appActions?.loadValidation(validationResult.schemaInvalidMessages)
39
39
  );
40
40
 
41
- if (validationResult.isSchemaValid) {
42
- await AppDependenceyProvider.getInstance()
43
- .getViewModelHandler()
44
- ?.updateModel(
45
- actionInvokerProps.viewModel.screenData,
46
- apiConfig,
47
- eventService
48
- );
41
+ if (!validationResult.isSchemaValid) return;
49
42
 
50
- handleNavigation(actionInvokerProps);
51
- }
43
+ await AppDependenceyProvider.getInstance()
44
+ .getViewModelHandler()
45
+ ?.updateModel(
46
+ actionInvokerProps.viewModel.screenData,
47
+ apiConfig,
48
+ eventService
49
+ );
50
+
51
+ // The response interceptor pushes server-side field errors into
52
+ // state.validation via FieldValidationDispatcher. Don't navigate away
53
+ // from a form the user still has to fix.
54
+ if (hasFieldValidationErrors(eventService)) return;
55
+
56
+ handleNavigation(actionInvokerProps);
52
57
  };
53
58
  export default handleUpdateAndNavigate;
@@ -0,0 +1,16 @@
1
+ import { eventServiceType } from "../../Constant";
2
+ import { EventService } from "../../Services/EventService";
3
+
4
+ // Reads the latest `state.app.validation` slice and returns true if any field
5
+ // currently carries one or more error messages. Used by save/update actions to
6
+ // skip navigation when server-side field validation has populated errors after
7
+ // the API call resolved.
8
+ export const hasFieldValidationErrors = (
9
+ eventService: EventService | undefined,
10
+ ): boolean => {
11
+ const appState = eventService?.emit(eventServiceType.APP_STATE);
12
+ const validation = (appState?.validation ?? {}) as Record<string, string[]>;
13
+ return Object.values(validation).some(
14
+ (messages) => Array.isArray(messages) && messages.length > 0,
15
+ );
16
+ };
@@ -5,6 +5,9 @@ import { IViewModelHandler } from "../DataModel/IViewModelHandler";
5
5
  import defaultResponseFormatter, {
6
6
  ResponseFormat,
7
7
  } from "../Services/helpers/coreResponseFormatter";
8
+ import defaultFieldErrorMapper, {
9
+ FieldErrorMapper,
10
+ } from "../Services/helpers/defaultFieldErrorMapper";
8
11
  import defaultSchemaBySlugService from "../Services/SchemaService";
9
12
 
10
13
  class UninitializedInstanceException extends Error {
@@ -25,6 +28,7 @@ export class AppDependenceyProvider {
25
28
  private _responseFormatter?:
26
29
  | ((data: any, status: number) => ResponseFormat)
27
30
  | undefined;
31
+ private _fieldErrorMapper?: FieldErrorMapper;
28
32
 
29
33
  private static instance: AppDependenceyProvider;
30
34
 
@@ -37,6 +41,7 @@ export class AppDependenceyProvider {
37
41
  requestHeaders,
38
42
  getSchemaBySlugService,
39
43
  responseFormatter,
44
+ fieldErrorMapper,
40
45
  }: any) {
41
46
  this._adapterProvider = adapterProvider;
42
47
  this._viewModelHandler = viewModelHandler;
@@ -46,6 +51,7 @@ export class AppDependenceyProvider {
46
51
  this._requestHeaders = requestHeaders;
47
52
  this._getSchemaBySlugService = getSchemaBySlugService;
48
53
  this._responseFormatter = responseFormatter;
54
+ this._fieldErrorMapper = fieldErrorMapper;
49
55
  }
50
56
 
51
57
  public static initInstance = ({
@@ -57,6 +63,7 @@ export class AppDependenceyProvider {
57
63
  requestHeaders,
58
64
  getSchemaBySlugService,
59
65
  responseFormatter,
66
+ fieldErrorMapper,
60
67
  }: any) => {
61
68
  if (!AppDependenceyProvider.instance)
62
69
  AppDependenceyProvider.instance = new AppDependenceyProvider({
@@ -68,6 +75,7 @@ export class AppDependenceyProvider {
68
75
  requestHeaders,
69
76
  getSchemaBySlugService,
70
77
  responseFormatter,
78
+ fieldErrorMapper,
71
79
  });
72
80
  };
73
81
 
@@ -115,4 +123,9 @@ export class AppDependenceyProvider {
115
123
  if (!this._responseFormatter) return defaultResponseFormatter;
116
124
  return this._responseFormatter;
117
125
  };
126
+
127
+ public getFieldErrorMapper = (): FieldErrorMapper => {
128
+ if (!this._fieldErrorMapper) return defaultFieldErrorMapper;
129
+ return this._fieldErrorMapper;
130
+ };
118
131
  }
@@ -0,0 +1,21 @@
1
+ type FieldErrors = Record<string, string[]>;
2
+ type Handler = (errors: FieldErrors) => void;
3
+
4
+ class FieldValidationDispatcher {
5
+ private static handler?: Handler;
6
+
7
+ static registerHandler(handler: Handler) {
8
+ FieldValidationDispatcher.handler = handler;
9
+ }
10
+
11
+ static dispatch(errors: FieldErrors) {
12
+ if (FieldValidationDispatcher.handler) {
13
+ FieldValidationDispatcher.handler(errors);
14
+ } else {
15
+ console.warn("Field validation dispatcher handler not registered.");
16
+ }
17
+ }
18
+ }
19
+
20
+ export default FieldValidationDispatcher;
21
+ export type { FieldErrors };
@@ -2,23 +2,34 @@ import { eventServiceType, LoadingStatus } from "../../Constant";
2
2
  import { appActions } from "../../Store/Slices/appSlice";
3
3
  import { metaDataActions } from "../../Store/Slices/metaDataSlice";
4
4
  import { commonDataActions } from "../../Store/Slices/commonDataSlice";
5
+ import FieldValidationDispatcher, {
6
+ FieldErrors,
7
+ } from "../HOC/FieldValidationDispatcher";
5
8
 
6
9
  let globalEventService: any = null;
7
10
 
8
11
  const setupStoreAction = (dispatch: any, eventService: any, store: any) => {
9
12
  globalEventService = eventService;
10
-
13
+
11
14
  const actions = {
12
15
  [eventServiceType.DATASTATE_ACTION]: appActions,
13
16
  [eventServiceType.UI_SCHEMA_ACTION]: metaDataActions,
14
17
  [eventServiceType.DISPATCH_STORE]: dispatch,
15
18
  [eventServiceType.DATASTATE]: () => store.getState().app.viewModel,
19
+ [eventServiceType.APP_STATE]: () => store.getState().app,
16
20
  };
17
21
 
18
22
  Object.entries(actions).forEach(([eventType, action]) => {
19
23
  eventService?.subscribe(eventType, () => action);
20
24
  });
21
25
 
26
+ // Route server-side field validation errors (alertType=fieldvalidation,
27
+ // typically 422) into the same redux slice the client validator writes to,
28
+ // so withValidations can render them under the relevant fields.
29
+ FieldValidationDispatcher.registerHandler((errors: FieldErrors) => {
30
+ dispatch(appActions.loadValidation(errors));
31
+ });
32
+
22
33
  // Register loader handlers for external services
23
34
  eventService?.subscribe(eventServiceType.REQUEST_START, () => () => {
24
35
  dispatch(commonDataActions.updatePendingRequests(LoadingStatus.INPROCESS));
package/src/Constant.ts CHANGED
@@ -33,6 +33,7 @@ export const eventServiceType = {
33
33
  UI_SCHEMA_ACTION: "UI_SCHEMA_ACTION",
34
34
  UISCHEMA: "UISCHEMA",
35
35
  DATASTATE: "DATASTATE",
36
+ APP_STATE: "APP_STATE",
36
37
  REQUEST_START: "REQUEST_START",
37
38
  REQUEST_END: "REQUEST_END",
38
39
  };