Skip to content

Commit

Permalink
migrated components with 'useExpressions'
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan committed May 3, 2023
1 parent 1363235 commit c101fb3
Show file tree
Hide file tree
Showing 14 changed files with 200 additions and 44 deletions.
2 changes: 1 addition & 1 deletion shesha-reactjs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@shesha/reactjs",
"version": "4.0.146-canary",
"version": "4.0.149-canary",
"description": "The reactjs frontend application and ui for the shesha framework",
"license": "GPL-3.0",
"homepage": "https://shesha-io.github.io/shesha-framework",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { IConfigurableColumnsProps } from '../../../../providers/datatableColumn
import { migrateV0toV1 } from './migrations/migrate-v1';
import { ITableViewProps } from '../../../../providers/tableViewSelectorConfigurator/models';
import { entityPickerSettings } from './settingsForm';
import { migrateDynamicExpression } from 'designer-components/_common-migrations/migrateUseExpression';

export interface IEntityPickerComponentProps extends IConfigurableFormComponent {
placeholder?: string;
Expand Down Expand Up @@ -88,13 +89,13 @@ const EntityPickerComponent: IToolboxComponent<IEntityPickerComponentProps> = {
addNewRecordsProps={
model?.allowNewRecord
? {
modalFormId: model?.modalFormId,
modalTitle: model?.modalTitle,
showModalFooter: model?.showModalFooter,
submitHttpVerb: model?.submitHttpVerb,
onSuccessRedirectUrl: model?.onSuccessRedirectUrl,
modalWidth: customWidth ? `${customWidth}${widthUnits}` : modalWidth,
}
modalFormId: model?.modalFormId,
modalTitle: model?.modalTitle,
showModalFooter: model?.showModalFooter,
submitHttpVerb: model?.submitHttpVerb,
onSuccessRedirectUrl: model?.onSuccessRedirectUrl,
modalWidth: customWidth ? `${customWidth}${widthUnits}` : modalWidth,
}
: undefined
}
name={model?.name}
Expand All @@ -116,8 +117,20 @@ const EntityPickerComponent: IToolboxComponent<IEntityPickerComponentProps> = {
})
.add<IEntityPickerComponentProps>(1, migrateV0toV1)
.add<IEntityPickerComponentProps>(2, prev => {
return { ...prev, useRawValues: true };
}),
return { ...prev, useRawValues: true };
})
.add<IEntityPickerComponentProps>(3, prev => {
const result = {...prev};
const useExpression = Boolean(result['useExpression']);
delete result['useExpression'];

if (useExpression){
const migratedExpression = migrateDynamicExpression(prev.filters);
result.filters = migratedExpression;
}

return result;
}),
settingsFormMarkup: entityPickerSettings,
validateSettings: model => validateConfigurableComponentSettings(entityPickerSettings, model),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { migrateV0toV1 } from './migrations/migrate-v1';
import { migrateV1toV2 } from './migrations/migrate-v2';
import classNames from 'classnames';
import { DEFAULT_CONFIRM_MESSAGE } from './constants';
import { migrateDynamicExpression } from 'designer-components/_common-migrations/migrateUseExpression';

/** @deprecated: Use DataListComponent instead */
const ListComponent: IToolboxComponent<IListComponentProps> = {
Expand Down Expand Up @@ -94,7 +95,19 @@ const ListComponent: IToolboxComponent<IListComponentProps> = {
return customProps;
})
.add<IListComponentProps>(1, migrateV0toV1)
.add<IListComponentProps>(2, migrateV1toV2),
.add<IListComponentProps>(2, migrateV1toV2)
.add<IListComponentProps>(3, prev => {
const result = {...prev};
const useExpression = Boolean(result['useExpression']);
delete result['useExpression'];

if (useExpression){
const migratedExpression = migrateDynamicExpression(prev.filters);
result.filters = migratedExpression;
}

return result;
}),
validateSettings: model => validateConfigurableComponentSettings(listSettingsForm, model),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import TimelineSettings from './settings';
import { evaluateValue } from '../../../../providers/form/utils';
import { ShaTimeline } from '../../../timeline/index';
import { ITimelineProps } from '../../../timeline/models';
import { migrateDynamicExpression } from 'designer-components/_common-migrations/migrateUseExpression';

const TimelineComponent: IToolboxComponent<ITimelineProps> = {
type: 'timeline',
Expand Down Expand Up @@ -40,6 +41,22 @@ const TimelineComponent: IToolboxComponent<ITimelineProps> = {
/>
);
},
migrator: m =>
m.add<ITimelineProps>(0, prev => {
const result: ITimelineProps = {
...prev,
entityType: prev['entityType'],
};
const useExpression = Boolean(result['useExpression']);
delete result['useExpression'];

if (useExpression){
const migratedExpression = migrateDynamicExpression(prev['filters'] ?? {});
result.filters = migratedExpression;
}

return result;
}),
};

export default TimelineComponent;
6 changes: 5 additions & 1 deletion shesha-reactjs/src/components/formDesigner/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const DesignerTemplate: Story<IFormDesignerStoryProps> = ({ formId }) => (
);

export const Bugfix = addStory(DesignerTemplate, {
formId: 'ed307f2d-e90e-4592-a4fe-b76748d33ce0'
formId: '7065cf3a-a8ec-494e-b2c8-273274b86d1f'
});

export const ColumnSettings = addStory(DesignerTemplate, {
Expand All @@ -41,6 +41,10 @@ export const CustomFunctions = addStory(DesignerTemplate, {
formId: '30c5cd95-e96d-4023-b213-94b1531ec6d9',
});

export const FormDetails = addStory(DesignerTemplate, {
formId: 'ac80013a-c02b-433b-b813-877422747a74',
});

export const FormsIndex = addStory(DesignerTemplate, {
formId: {
name: 'forms',
Expand Down
1 change: 1 addition & 0 deletions shesha-reactjs/src/components/timeline/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ export interface ITimelineProps extends IConfigurableFormComponent, ICommonConta
dataSource?: 'form' | 'api';
customApiUrl?: string;
apiSource?: 'entity' | 'custom';
filters?: object;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { ITableViewProps } from "providers/tableViewSelectorConfigurator/models";

interface IArgumentEvaluationResult {
handled: boolean;
value?: any;
}
type JsonLogicContainerProcessingCallback = (operator: string, args: object[], argIndex: number) => IArgumentEvaluationResult;

const convertJsonLogicNode = (jsonLogic: object, argumentEvaluator: JsonLogicContainerProcessingCallback): object => {
if (!jsonLogic)
return null;

const result = {};
for (const operator in jsonLogic) {
if (!jsonLogic.hasOwnProperty(operator))
continue;

const args = jsonLogic[operator];

let convertedArgs = null;

if (Array.isArray(args)) {
convertedArgs = args.map((arg, argIdx) => {
if (typeof (arg) === 'object')
return convertJsonLogicNode(arg, argumentEvaluator);

const evaluationResult = argumentEvaluator(operator, args, argIdx);
return evaluationResult.handled
? evaluationResult.value
: arg;
});
} else {
// note: single arguments may be presented as objects, example: {"!!": {"var": "user.userName"}}
if (typeof (args) === 'object') {
convertedArgs = convertJsonLogicNode(args, argumentEvaluator);
} else {
const evaluationResult = argumentEvaluator(operator, [args], 0);
convertedArgs = evaluationResult.handled
? evaluationResult.value
: args;
}
}
result[operator] = convertedArgs;
}
return result;
};

export const migrateDynamicExpression = (expression: any): object => {
try {
const parsedExpression = typeof(expression) === 'string' ? JSON.parse(expression) : expression;

const convertedExpression = convertJsonLogicNode(parsedExpression, (_operator: string, args: object[], argIndex: number) => {
const argValue = args[argIndex];
if (argValue && typeof(argValue) === 'string' && (argValue as string).includes('{{')){
return {
handled: true,
value: { evaluate: [ { expression: argValue, type: 'text' } ] },
};
}
return {
handled: false
};
});
return convertedExpression;
} catch(error) {
console.error('Failed to parse expression', error);
return expression;
};
};

export const migrateFilterMustacheExpressions = (filter: ITableViewProps): ITableViewProps => {
const useExpression = Boolean(filter['useExpression']);
if (!useExpression)
return filter;

delete filter['useExpression'];
const { expression } = filter;

const convertedExpression = migrateDynamicExpression(expression);
return { ...filter, expression: convertedExpression };
};
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { isEmpty } from 'lodash';
import camelCaseKeys from 'camelcase-keys';
import { evaluateDynamicFilters } from '../../providers/dataTable/utils';
import { IAutocompleteComponentProps } from './interfaces';
import { migrateDynamicExpression } from 'designer-components/_common-migrations/migrateUseExpression';

interface IQueryParams {
// tslint:disable-next-line:typedef-whitespace
Expand Down Expand Up @@ -178,14 +179,23 @@ const AutocompleteComponent: IToolboxComponent<IAutocompleteComponentProps> = {
},
settingsFormMarkup: settingsForm,
validateSettings: model => validateConfigurableComponentSettings(settingsForm, model),
initModel: model => {
const customProps: IAutocompleteComponentProps = {
...model,
dataSourceType: 'entitiesList',
useRawValues: false,
};
return customProps;
},
migrator: m => m.add<IAutocompleteComponentProps>(0, prev => ({
...prev,
dataSourceType: prev['dataSourceType'] ?? 'entitiesList',
useRawValues: prev['useRawValues'] ?? false,
}))
.add<IAutocompleteComponentProps>(1, prev => {
const result = {...prev};
const useExpression = Boolean(result['useExpression']);
delete result['useExpression'];

if (useExpression){
const migratedExpression = migrateDynamicExpression(prev.filter);
result.filter = migratedExpression;
}

return result;
}),
linkToModelMetadata: (model, metadata): IAutocompleteComponentProps => {
return {
...model,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface IAutocompleteComponentProps extends IConfigurableFormComponent
queryParams?: IQueryParamProp[];
keyPropName?: string;
valuePropName?: string;
filter?: string;
filter?: object;
disableSearch?: boolean;
placeholder?: string;
quickviewEnabled?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import _, { isEmpty } from 'lodash';
import { migrateV0toV1 } from './migrations/migrate-v1';
import { migrateV1toV2 } from './migrations/migrate-v2';
import { useDeepCompareEffect } from 'react-use';
import { migrateV2toV3 } from './migrations/migrate-v3';

export interface IChildTableComponentProps extends IChildTableSettingsProps, IConfigurableFormComponent {
components?: IConfigurableFormComponent[];
Expand Down Expand Up @@ -185,10 +186,6 @@ const ChildTableComponent: IToolboxComponent<IChildTableComponentProps> = {
);
},
validateSettings: model => validateConfigurableComponentSettings(settingsForm, model),
initModel: model => ({
...model,
isNotWrapped: true,
}),
migrator: m =>
m
.add<IChildTableComponentProps>(0, prev => {
Expand All @@ -199,7 +196,8 @@ const ChildTableComponent: IToolboxComponent<IChildTableComponentProps> = {
};
})
.add<IChildTableComponentProps>(1, migrateV0toV1)
.add<IChildTableComponentProps>(2, migrateV1toV2),
.add<IChildTableComponentProps>(2, migrateV1toV2)
.add<IChildTableComponentProps>(3, migrateV2toV3),
};

export default ChildTableComponent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { migrateFilterMustacheExpressions } from "designer-components/_common-migrations/migrateUseExpression";
import { IChildTableComponentProps } from "..";
import { SettingsMigrationContext } from "interfaces/formDesigner";

export const migrateV2toV3 = (props: IChildTableComponentProps, _context: SettingsMigrationContext): IChildTableComponentProps => {
const { filters } = props;

return {
...props,
filters: filters?.map(filter => migrateFilterMustacheExpressions(filter)) ?? []
};
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { IConfigurableFormComponent } from '../../../providers/form/models';
import { ITableViewProps } from '../../../providers/tableViewSelectorConfigurator/models';
import { MutableRefObject } from 'react';

export interface ITableViewSelectorProps extends IConfigurableFormComponent {
export interface ITableViewSelectorComponentProps extends IConfigurableFormComponent {
filters: ITableViewProps[];
persistSelectedFilters?: boolean;
componentRef: MutableRefObject<any>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { FC, MutableRefObject } from 'react';
import { IToolboxComponent } from '../../../interfaces';
import { SelectOutlined } from '@ant-design/icons';
import TableViewSelectorSettings from './tableViewSelectorSettings';
import { ITableViewSelectorProps } from './models';
import { ITableViewSelectorComponentProps } from './models';
import { useForm } from '../../..';
import { useDataTableStore, useGlobalState } from '../../../providers';
import { evaluateDynamicFilters } from '../../../providers/dataTable/utils';
Expand All @@ -11,26 +11,31 @@ import _ from 'lodash';
import { Alert } from 'antd';
import { useDeepCompareEffect } from 'react-use';
import TableViewSelectorRenderer from '../../../components/tableViewSelectorRenderer';
import { migrateFilterMustacheExpressions } from 'designer-components/_common-migrations/migrateUseExpression';

const TableViewSelectorComponent: IToolboxComponent<ITableViewSelectorProps> = {
const TableViewSelectorComponent: IToolboxComponent<ITableViewSelectorComponentProps> = {
type: 'tableViewSelector',
name: 'Table view selector',
icon: <SelectOutlined />,
factory: (model: ITableViewSelectorProps, componentRef: MutableRefObject<any>) => {
return <TableViewSelector componentRef={componentRef} {...model} />;
factory: (model: ITableViewSelectorComponentProps, componentRef: MutableRefObject<any>) => {
return <TableViewSelector {...model} componentRef={componentRef}/>;
},
initModel: (model: ITableViewSelectorProps) => {
migrator: m => m.add<ITableViewSelectorComponentProps>(0, prev => {
return {
...model,
title: 'Title',
filters: [],
...prev,
title: prev['title'] ?? 'Title',
filters: prev['filters'] ?? [],
componentRef: prev['componentRef'],
};
},
})
.add(1, prev => (
{...prev, filters: prev.filters.map(filter => migrateFilterMustacheExpressions(filter))}
)),
settingsFormFactory: ({ readOnly, model, onSave, onCancel, onValuesChange }) => {
return (
<TableViewSelectorSettings
readOnly={readOnly}
model={model as ITableViewSelectorProps}
model={model as ITableViewSelectorComponentProps}
onSave={onSave}
onCancel={onCancel}
onValuesChange={onValuesChange}
Expand All @@ -39,6 +44,10 @@ const TableViewSelectorComponent: IToolboxComponent<ITableViewSelectorProps> = {
},
};

interface ITableViewSelectorProps extends ITableViewSelectorComponentProps {
componentRef: MutableRefObject<any>;
}

export const TableViewSelector: FC<ITableViewSelectorProps> = ({ filters, componentRef, persistSelectedFilters }) => {
const {
columns,
Expand Down
Loading

0 comments on commit c101fb3

Please sign in to comment.