From 21694c63734f3471f40f5aa3353df41452fa9a21 Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Wed, 9 Oct 2024 14:25:46 +0200 Subject: [PATCH] WIP --- webpack/app/components/TableCell.coffee | 1104 ++++++++++++++++++++++- webpack/app/senaite.timeseries.js | 19 +- 2 files changed, 1099 insertions(+), 24 deletions(-) diff --git a/webpack/app/components/TableCell.coffee b/webpack/app/components/TableCell.coffee index 6f67d0b..b95751f 100644 --- a/webpack/app/components/TableCell.coffee +++ b/webpack/app/components/TableCell.coffee @@ -1,25 +1,1089 @@ -React = require 'react' -class TableCell extends React.Component +import React from "react" + +import Checkbox from "SenaiteAppListing/Checkbox.coffee" +import HiddenField from "SenaiteAppListing/HiddenField.coffee" +import MultiChoice from "SenaiteAppListing/MultiChoice.coffee" +import MultiSelect from "SenaiteAppListing/MultiSelect.coffee" +import MultiValue from "SenaiteAppListing/MultiValue.coffee" +import TimeSeries from "./TimeSeries.coffee" +import NumericField from "SenaiteAppListing/NumericField.coffee" +import CalculatedField from "SenaiteAppListing/CalculatedField.coffee" +import ReadonlyField from "SenaiteAppListing/ReadonlyField.coffee" +import Select from "SenaiteAppListing/Select.coffee" +import StringField from "SenaiteAppListing/StringField.coffee" +import TextField from "SenaiteAppListing/TextField.coffee" +import FractionField from "SenaiteAppListing/FractionField.coffee" +import DateTime from "SenaiteAppListing/DateTime.coffee" + + +class TableCell extends React.Component constructor: (props) -> super(props) + # Zope Publisher Converter Argument Mapping + @ZPUBLISHER_CONVERTER = { + "boolean": ":record:ignore_empty" + "select": ":records" + "choices": ":records" + "multiselect": ":list" + "multichoice": ":list" + "multivalue": ":list" + "timeseries": ":list" + "numeric": ":records" + "fraction": ":records" + "string": ":records" + "text": "records" + "datetime": ":records" + "readonly": "" + "default": ":records" + } + + get_column: -> + return @props.column + + get_item: -> + return @props.item + + get_column_key: -> + return @props.column_key + + render_before_content: (props={}) -> + column_key = @get_column_key() + item = @get_item() + return unless item + before = item.before + if column_key not of before + return null + # support to render React components + before_components = item.before_components or {} + return ( + + {before_components[column_key]} + + ) + + render_after_content: (props={}) -> + column_key = @get_column_key() + item = @get_item() + return unless item + after = item.after + if column_key not of after + return null + # support to render React components + after_components = item.after_components or {} + return ( + + {after_components[column_key]} + + ) + + is_edit_allowed: -> + column_key = @get_column_key() + item = @get_item() + + # the global allow_edit overrides all row specific settings + if not @props.allow_edit + return no + + # check if the field is listed in the item's allow_edit list + if column_key in item.allow_edit + return yes + + return no + + is_disabled: -> + item = @get_item() + disabled = item.disabled + if disabled in [yes, no] + return disabled + + return no unless disabled? + + # check if the field is listed in the item's disabled list + column_key = @get_column_key() + return column_key in disabled + + is_required: -> + column_key = @get_column_key() + item = @get_item() + required_fields = item.required or [] + required = column_key in required_fields + # make the field conditionally required if the row is selected + selected = @props.selected + return required and selected + + get_name: -> + uid = @get_uid() + column_key = @get_column_key() + return "#{column_key}.#{uid}" + + get_uid: -> + item = @get_item() + return item.uid + + is_selected: -> + item = @get_item() + return item.uid in @props.selected_uids + + get_value: -> + column_key = @get_column_key() + item = @get_item() + value = item[column_key] + + # check if the field is an interim + interims = @get_interimfields() + if interims.hasOwnProperty column_key + # extract the value from the interim field + # {value: "", keyword: "", formatted_value: "", unit: "", title: ""} + value = interims[column_key].value or "" + + # values of input fields should not be null + if value is null + value = "" + + return value + + ### + Returns the size for the folderitem or interim field + ### + get_size: -> + default_size = 5 + types_size = + "string": 30, + "text": 30, + + item = @get_item() + column_key = @get_column_key() + + # Maybe the size is defined in the interim field + if @is_interimfield() + interim = item[column_key] + if interim and interim.hasOwnProperty "size" + return interim.size + + # check the size for this field is defined in current item + sizes = item.size or {} + if column_key of sizes + return sizes[column_key] + + # maybe the size is defined in the column + column = @props.column or {} + if "size" of column + return column.size + + # return default by type + type = @get_type() + if type of types_size + return types_size[type] + + return default_size + + ###* + * Create a mapping of interim keyword -> interim field + * + * Interim fields are record fields with a format like this: + * {value: "", keyword: "", formatted_value: "", unit: "", title: ""} + ### + get_interimfields: -> + item = @get_item() + interims = item.interimfields or [] + mapping = {} + interims.map (item, index) -> + mapping[item.keyword] = item + return mapping + + is_interimfield: -> + column_key = @get_column_key() + interims = @get_interimfields() + return interims.hasOwnProperty column_key + + get_choices: -> + item = @get_item() + return item.choices or {} + + is_result_column: -> + column_key = @get_column_key() + if column_key == "Result" + return yes + return no + + get_formatted_value: -> + column_key = @get_column_key() + item = @get_item() + # replacement html or plain value of the current column + formatted_value = item.replace[column_key] or @get_value() + # use the formatted result + if @is_result_column() + formatted_value = item.formatted_result or formatted_value + return formatted_value + + get_type: -> + column_key = @get_column_key() + item = @get_item() + + # true if the field is editable + editable = @is_edit_allowed() + resultfield = @is_result_column() + + # timeseries field + if resultfield and item.result_type == "timeseries_readonly" + return item.result_type + + # readonly field + if not editable + return "readonly" + + # calculated fields are also in editable mode readonly + if resultfield and item.calculation + return "calculated" + + # check if the field is a string or datetime field + if resultfield and item.result_type + return item.result_type + + # type definition of the column has precedence + column = @props.column or {} + if "type" of column + return column["type"] + + # check if the field is a boolean + value = @get_value() + if typeof(value) == "boolean" + return "boolean" + + # check if the field is listed in choices + choices = @get_choices() + if column_key of choices + # check if the field is a multi-choices + default_type = "select" + if resultfield + return item.result_type or default_type + # Maybe is an interim field + if @is_interimfield() + column_key = @get_column_key() + interim = item[column_key] + if interim + return interim.result_type or default_type + return default_type + + # check if the field is an interim + if @is_interimfield() + default_type = "interim" + column_key = @get_column_key() + interim = item[column_key] + if interim + return interim.result_type or default_type + return default_type + + # the default + return "numeric" + + ###* + * Creates a readonly field component + * + * The passed in `props` allow to override required values + * + * @param props {object} properties passed to the component + * @returns ReadonlyField component + ### + create_readonly_field: ({props}={}) -> + props ?= {} + + column_key = props.column_key or @get_column_key() + item = props.item or @get_item() + name = props.name or @get_name() + value = props.value or @get_value() + formatted_value = props.formatted_value or @get_formatted_value() + uid = props.uid or @get_uid() + css_class = props.css_class or "readonly" + + return ( + ) + + ###* + * Creates a calculated field component + * + * The passed in `props` allow to override required values + * + * @param props {object} properties passed to the component + * @returns CalculatedField component + ### + create_calculated_field: ({props}={}) -> + props ?= {} + + column_key = props.column_key or @get_column_key() + item = props.item or @get_item() + name = props.name or @get_name() + value = props.value or @get_value() + formatted_value = props.formatted_value or @get_formatted_value() + uid = props.uid or @get_uid() + title = props.title or @props.column.title or column_key + + column = props.column or @get_column() + item.help ?= {} + help = props.help or item.help[column_key] or column.help + + selected = props.selected or @is_selected() + required = props.required or @is_required() + size = props.size or @get_size() + css_class = props.css_class or "form-control form-control-sm calculated" + if required then css_class += " required" + + return ( + ) + + ###* + * Creates a hidden field component + * + * The passed in `props` allow to override required values + * + * @param props {object} properties passed to the component + * @returns HiddenField component + ### + create_hidden_field: ({props}={}) -> + props ?= {} + + column_key = props.column_key or @get_column_key() + item = props.item or @get_item() + name = props.name or @get_name() + value = props.value or @get_value() + uid = props.uid or @get_uid() + title = props.title or @props.column.title or column_key + + return ( + ) + + ###* + * Creates a numeric field component + * + * The passed in `props` allow to override required values + * + * @param props {object} properties passed to the component + * @returns NumericField component + ### + create_numeric_field: ({props}={}) -> + props ?= {} + + column_key = props.column_key or @get_column_key() + item = props.item or @get_item() + name = props.name or @get_name() + value = props.value or @get_value() + formatted_value = props.formatted_value or @get_formatted_value() + uid = props.uid or @get_uid() + title = props.title or @props.column.title or column_key + + column = props.column or @get_column() + item.help ?= {} + help = props.help or item.help[column_key] or column.help + + converter = @ZPUBLISHER_CONVERTER["numeric"] + fieldname = name + converter + + selected = props.selected or @is_selected() + disabled = props.disabled or @is_disabled() + required = props.required or @is_required() + size = props.size or @get_size() + css_class = props.css_class or "form-control form-control-sm" + if required then css_class += " required" + + return ( + ) + + ###* + * Creates a string field component + * + * The passed in `props` allow to override required values + * + * @param props {object} properties passed to the component + * @returns StringField component + ### + create_string_field: ({props}={}) -> + props ?= {} + + column_key = props.column_key or @get_column_key() + item = props.item or @get_item() + name = props.name or @get_name() + value = props.value or @get_value() + formatted_value = props.formatted_value or @get_formatted_value() + uid = props.uid or @get_uid() + title = props.title or @props.column.title or column_key + + column = props.column or @get_column() + item.help ?= {} + help = props.help or item.help[column_key] or column.help + + converter = @ZPUBLISHER_CONVERTER["string"] + fieldname = name + converter + + selected = props.selected or @is_selected() + disabled = props.disabled or @is_disabled() + required = props.required or @is_required() + size = props.size or @get_size() + css_class = props.css_class or "form-control form-control-sm" + if required then css_class += " required" + + return ( + ) + + ###* + * Creates a text field component + * + * The passed in `props` allow to override required values + * + * @param props {object} properties passed to the component + * @returns TextField component + ### + create_text_field: ({props}={}) -> + props ?= {} + + column_key = props.column_key or @get_column_key() + item = props.item or @get_item() + name = props.name or @get_name() + value = props.value or @get_value() + formatted_value = props.formatted_value or @get_formatted_value() + uid = props.uid or @get_uid() + title = props.title or @props.column.title or column_key + + column = props.column or @get_column() + item.help ?= {} + help = props.help or item.help[column_key] or column.help + + converter = @ZPUBLISHER_CONVERTER["text"] + fieldname = name + converter + + selected = props.selected or @is_selected() + disabled = props.disabled or @is_disabled() + required = props.required or @is_required() + size = props.size or @get_size() + css_class = props.css_class or "form-control form-control-sm" + if required then css_class += " required" + + return ( + ) + + ###* + * Creates a fraction field component + * + * The passed in `props` allow to override required values + * + * @param props {object} properties passed to the component + * @returns NumericField component + ### + create_fraction_field: ({props}={}) -> + props ?= {} + + column_key = props.column_key or @get_column_key() + item = props.item or @get_item() + name = props.name or @get_name() + value = props.value or @get_value() + formatted_value = props.formatted_value or @get_formatted_value() + uid = props.uid or @get_uid() + title = props.title or @props.column.title or column_key + + column = props.column or @get_column() + item.help ?= {} + help = props.help or item.help[column_key] or column.help + + converter = @ZPUBLISHER_CONVERTER["fraction"] + fieldname = name + converter + + selected = props.selected or @is_selected() + disabled = props.disabled or @is_disabled() + required = props.required or @is_required() + size = props.size or @get_size() + css_class = props.css_class or "form-control form-control-sm" + if required then css_class += " required" + + return ( + ) + + ###* + * Creates a datetime field component + * + * The passed in `props` allow to override required values + * + * @param props {object} properties passed to the component + * @returns DateTime component + ### + create_datetime_field: ({props}={}) -> + props ?= {} + + column_key = props.column_key or @get_column_key() + item = props.item or @get_item() + name = props.name or @get_name() + value = props.value or @get_value() + type = props.type or @get_type() + formatted_value = props.formatted_value or @get_formatted_value() + uid = props.uid or @get_uid() + title = props.title or @props.column.title or column_key + + column = props.column or @get_column() + item.help ?= {} + help = props.help or item.help[column_key] or column.help + + result_type = "date" + converter = @ZPUBLISHER_CONVERTER["string"] + fieldname = name + converter + + selected = props.selected or @is_selected() + disabled = props.disabled or @is_disabled() + required = props.required or @is_required() + size = props.size or @get_size() + css_class = props.css_class or "form-control form-control-sm" + + if required then css_class += " required" + + # min/max dates + min = column.min or null + max = column.max or null + + if min + [min_date, min_time] = min.split(" ") + if max + [max_date, max_time] = max.split(" ") + + return ( + ) + + ###* + * Creates a select field component + * + * The passed in `props` allow to override required values + * + * @param props {object} properties passed to the component + * @returns SelectField component + ### + create_select_field: ({props}={}) -> + props ?= {} + + column_key = props.column_key or @get_column_key() + item = props.item or @get_item() + name = props.name or @get_name() + value = props.value or @get_value() + formatted_value = props.formatted_value or @get_formatted_value() + uid = props.uid or @get_uid() + title = props.title or @props.column.title or column_key + options = props.options or item.choices[column_key] or [] + + column = props.column or @get_column() + item.help ?= {} + help = props.help or item.help[column_key] or column.help + + converter = @ZPUBLISHER_CONVERTER["select"] + fieldname = name + converter + + selected = props.selected or @is_selected() + disabled = props.disabled or @is_disabled() + required = props.required or @is_required() + size = props.size or @get_size() + css_class = props.css_class or "form-control form-control-sm" + if required then css_class += " required" + + return ( +