Skip to content

Commit

Permalink
Support both string and real value
Browse files Browse the repository at this point in the history
  • Loading branch information
Paulo Andre Azevedo Quirino committed Sep 6, 2024
1 parent 2e52137 commit 48d7169
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 231 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const ParametersTable = props => {
// Props
const { editable, data, openEditDialog, onRowDelete, defaultColumns } = props;
// Hooks
const { getLabel } = useDataTypes();
const { getLabel } = useDataTypes({ onlyStrings: true });
// Override default columns
const typeColumn = {
title: i18n.t("Type"),
Expand Down
17 changes: 5 additions & 12 deletions src/editors/_shared/KeyValueTable/ParametersEditorDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ const ParameterEditorDialog = props => {
const [data, setData] = useState({});
const [valueOption, setValueOption] = useState(VALUE_OPTIONS.DEFAULT);
const classes = parametersDialogStyles();
const { getDataTypes, getLabel, getEditComponent, getValidValue, validate } =
useDataTypes();
const { getDataTypes, getLabel, getEditComponent, getValidValue, validate, getType } =
useDataTypes({ onlyStrings: true });

//========================================================================================
/* *
Expand Down Expand Up @@ -90,11 +90,9 @@ const ParameterEditorDialog = props => {
}
}

return typeof formData.value !== "string"
? JSON.stringify(formData.value)
: formData.value;
return getType(formData.type).getSaveable(formData.value);
},
[showValueOptions, valueOption]
[showValueOptions, valueOption, getType]
);

/**
Expand Down Expand Up @@ -159,13 +157,8 @@ const ParameterEditorDialog = props => {

if (customValidation) return customValidation(dataToValidate);

// If value is DEFAULT_VALUE, the parameter should be removed
// Therefore we can by-pass the validation in that case
if (dataToValidate.value === DEFAULT_VALUE)
return Promise.resolve({ success: true, data: dataToValidate });

// Validate data
return validate(data.value, getValidationOptions())
return validate(dataToValidate, getValidationOptions())
.then(res => {
if (!res.success)
throw new Error(
Expand Down
102 changes: 58 additions & 44 deletions src/editors/_shared/hooks/DataTypes/AbstractDataType.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,45 @@ import { TextField, Typography } from "@material-ui/core";
import { MonacoCodeEditor } from "@mov-ai/mov-fe-lib-code-editor";
import { DATA_TYPES } from "../../../../utils/Constants";

const identity = a => a;

/**
* Abstract Data Type Class
*/
class AbstractDataType {
key = "";
label = "";
default = "";
inputType = "text";

editComponent = this.defaultStringEditor;
// hooks
_theme = {};

constructor({ theme }) {
constructor({ theme, onlyStrings }) {
// Set hooks to be used in abstract renders
this._theme = theme;
this.defaultStringEditor = this.defaultStringEditor.bind(this);
this.onlyStrings = onlyStrings;
this.parsing = onlyStrings
? { parse: identity, unparse: identity } : {
parse: this.parse.bind(this),
unparse: this.unparse.bind(this)
};
this.getSaveable = onlyStrings ? this.unparse.bind(this) : identity;
}

// parsing strings into real objects
parse(value) {
return JSON.parse(value);
}

// unparsing real objects into strings
unparse(value) {
return typeof(value) === "string" ? value : JSON.stringify(value);
}

// ensure a parsed value. runs only for validation
getParsed(value) {
return this.onlyStrings ? this.parse(value) : value;
}

/**
Expand All @@ -43,23 +66,29 @@ class AbstractDataType {
* @returns
*/
getEditComponent() {
return this.editComponent;
return (...args) => this.editComponent(...args);
}

/**
* Abstract validation : Should fail if not implemented in extended class
* Abstract validation : validation for simple types
* @returns
*/
validate() {
// To be implemented in extended class
console.warn(
"debug validation method not implemented for data type",
this.key
);
return Promise.resolve({
success: false,
error: "ValidationMethodNotImplemented"
});
_validate(value) {
return typeof value === this.key;
}

/**
* Abstract validation : validation for simple types
* @returns
*/
validate(value) {
try {
return Promise.resolve({
success: this._validate(this.getParsed(value))
});
} catch (_e) {
return Promise.resolve({ success: false });
}
}

/**
Expand All @@ -68,7 +97,7 @@ class AbstractDataType {
* @returns {any} Default value
*/
getDefault(options) {
return this.default;
return this.parsing.unparse(this.default);
}

//========================================================================================
Expand All @@ -83,7 +112,7 @@ class AbstractDataType {
* @returns {string} String value
*/
toString(value) {
return _toString(value);
return this.parsing.unparse(value);
}

/**
Expand All @@ -92,7 +121,7 @@ class AbstractDataType {
* @returns parsed value
*/
getParsedValue(value) {
return typeof value === DATA_TYPES.STRING ? JSON.parse(value) : value;
return this.parsing.parse(value);
}

/**
Expand All @@ -101,9 +130,9 @@ class AbstractDataType {
* @param {*} mode
* @returns
*/
defaultStringEditor(props, mode = "row") {
editComponent(props, mode = "row") {
const editor = {
row: _props => this.stringEditComponent(_props, ""),
row: _props => this.stringEditComponent(_props, undefined),
dialog: _props => this.codeEditComponent(_props)
};
return editor[mode](props);
Expand All @@ -112,29 +141,21 @@ class AbstractDataType {
/**
* @private Gets common text editor for regular inputs (strings, arrays, objects, any, default)
* @param {*} props : Material table row props
* @param {string} placeholder : Placeholder
* @param {*} parsedValue : Parsed value (can be a string, array, or object)
* @returns {ReactComponent} Text input for editing common strings
*/
stringEditComponent(props, placeholder, parsedValue, options = {}) {
const { parse = a => a, unparse = a => a } = options;

stringEditComponent(props, parsedValue) {
const value = (parsedValue !== undefined ? parsedValue : props.rowData.value) ?? "";

return (
<TextField
inputProps={{ "data-testid": "input_value" }}
fullWidth
placeholder={placeholder}
defaultValue={unparse(value)}
onChange={evt => {
try {
const parsedValue = parse(evt.target.value);
props.onChange(parsedValue);
} catch (e) {
props.onChange(evt.target.value);
}
}}
type={this.inputType}
placeholder={this.getDefault()}
defaultValue={this.parsing.unparse(value)}
disabled={props.disabled}
onChange={evt => props.onChange(this.parsing.parse(evt.target.value))}
></TextField>
);
}
Expand All @@ -144,17 +165,15 @@ class AbstractDataType {
* @param {{rowData: {value: string}}, onChange: function, isNew: boolean} props : input props
* @returns {ReactComponent} Code Editor Component
*/
codeEditComponent = (props, options = {}) => {
const { parse = a => a, unparse = a => a } = options;

codeEditComponent = (props) => {
return (
<Typography
data-testid="section_data-type-code-editor"
component="div"
style={{ height: "100px", width: "100%" }}
>
<MonacoCodeEditor
value={unparse(props.rowData.value)}
value={this.parsing.unparse(props.rowData.value)}
onLoad={editor => {
if (!props.isNew) editor.focus();
props.onLoadEditor && props.onLoadEditor(editor);
Expand All @@ -163,12 +182,7 @@ class AbstractDataType {
disableMinimap={true}
theme={this._theme?.codeEditor?.theme ?? "dark"}
options={{ readOnly: props.disabled }}
onChange={value => {
try {
const parsedValue = parse(value);
props.onChange(parsedValue);
} catch (e) {}
}}
onChange={value => props.onChange(this.parsing.parse(value))}
/>
</Typography>
);
Expand Down
5 changes: 3 additions & 2 deletions src/editors/_shared/hooks/DataTypes/DataTypeManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import ObjectType from "./types/ObjectType";
import StringType from "./types/StringType";

class DataTypeManager {
constructor({ theme, selfProvision = true }) {
constructor({ theme, selfProvision = true, onlyStrings = false }) {
this.onlyStrings = onlyStrings;
// Hooks
this.theme = theme;
// Initiate types
Expand All @@ -28,7 +29,7 @@ class DataTypeManager {
* @param {DataType} DataType : DataType class
*/
setDataType(DataType) {
const dataTypeInstance = new DataType({ theme: this.theme });
const dataTypeInstance = new DataType({ theme: this.theme, onlyStrings: this.onlyStrings });
this.dataTypes.set(dataTypeInstance.getKey(), dataTypeInstance);
}

Expand Down
5 changes: 2 additions & 3 deletions src/editors/_shared/hooks/DataTypes/types/AnyType.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ class AnyType extends DataType {
// Any type properties definition
key = DATA_TYPES.ANY;
label = "Any";
editComponent = this.defaultStringEditor;

/**
* Validate value
* @param {*} value
* @returns
*/
validate(value) {
return Promise.resolve({ success: true, value });
_validate(value) {
return true;
}
}

Expand Down
18 changes: 2 additions & 16 deletions src/editors/_shared/hooks/DataTypes/types/ArrayType.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,19 @@ import { DATA_TYPES } from "../../../../../utils/Constants";
import DataType from "../AbstractDataType";
import { checkIfDefaultOrDisabled } from "./utils";

const objectOptions = {
parse: a => JSON.parse(a),
// Check if value is a string since there are instances where objects were saved as strings
unparse: a => typeof(a) === "string" ? a : JSON.stringify(a),
};

class ArrayType extends DataType {
// Array type properties definition
key = DATA_TYPES.ARRAY;
label = "Array";
default = [];

editComponent = (props, mode = "row") => {
const editor = {
row: _props => this.stringEditComponent(_props, this.default, undefined, objectOptions),
dialog: props => this.codeEditComponent(props, objectOptions),
};
return editor[mode](props);
};

/**
* Validate array value
* @param {*} value
* @returns
*/
validate(value) {
return Promise.resolve({ success: Array.isArray(value) });
_validate(value) {
return Array.isArray(value);
}
}

Expand Down
Loading

0 comments on commit 48d7169

Please sign in to comment.