CuneiTable
CuneiTable is designed specifically to enable in-line data entry. Design-wise, it is more limited than CuneiForm since design flexibility is not highly expected from table-rype objects. In essence, CuneiTable is a wrapper for the accompanying CuneiForm, whether that form be the in-line type or the full expansion type.
Define
Defining a CuneiTable is essentially declaring a CuneiForm with a few additional class variables. Below is an example of a very basic CuneiTable:
class AccCodeTable(CuneiTable):
MASTER_colsizes = [10, 20, 50, 20]
MASTER_colnames = ["StID", "Account Code", "Account Name", "Account Group"]
MASTER_coltypes = ["int", "str", "str", "sel"]
MASTER_choicecols = ["accgrp"]
MASTER_choices = [[
("1", "Asset"),
("2", "Liability"),
("3", "Equity"),
("4", "Revenue"),
("5", "Expense")
]]
MASTER_firstonly = ["stid"]
class SubForm(FlaskForm, CuneiSubForm):
stid = StringField("StID")
code = StringField("Code", validators=[InputRequired("Required!")])
name = StringField("Name", validators=[InputRequired("Required!")])
accgrp = SelectField("Group", default=1)
def validate_stid(self, stid):
# Validation goes here
The subclass SubForm is defined like the stripped down version of CuneiForm. Only put fields and validation logics here. All other behaviours are controlled by the MASTER variables from the CuneiTable level.
NOTE THAT neither of the Submit-delete Field Set (submit
, is_del
, and del_submit
) is declared in the SubForm. These fields are taken care of automatically during CuneiTable initiation.
The Holy Trinity of CuneiTable
The 3 MASTER variables listed below are required for all CuneiTable classes.
MASTER_colnames
([str,]): The list of column headers to appear on the page.MASTER_coltypes
([str,]): The list of column value types. Available types include:- All types listed in the main article for CuneiForm.
'str'
: Normal string value.'check'
: Value represented by a checkbox.'sel'
: Value with multiple choices. In other words, this is equivalent to a drop-list field in forms. In the same fashion, the displayed values for this type is not exactly the same as the values stored in the database. The raw value must pass through a map first before being displayed.'rad'
: Similar to'sel'
, but this value type is represented by radio buttons in multiple sub-columns instead.'submit'
,'del_submit'
: Submit button. (Not handled manually, they are handled automatically during initiation.)
MASTER_colsizes
([float/int,]): The list of relative column sizes. CuneiFox will calculate the display sizes automatically.
NOTE #1: The member order in each of these lists follow the definition order of fields in the SubForm. DO CHECK that all of these 3 lists and the SubForm fields share the same length.
NOTE #2: On the client-side, a radio field ('rad'
) is displayed as multiple sub-columns (one for each choice). Hence:
- The display headers of sub-columns are not dictated by the corresponding value in MASTER_colnames, but by the values in MASTER_radios (Detailed in a sub-section below) instead.
- The corresponding member in the MASTER_colsizes list is NOT merely one numerical value, BUT a list of numerical values instead.
Choices and Radios
Columns with limited choices of predesignated values should utilize 'choice' or 'radio' representation; especially when the stored values must be mapped to another set of more readable or localizable display values. Ideally:
- Columns utilizing choice representation is typed
'sel'
(MASTER_coltypes[i] = 'sel'
), and the corresponding field in the SubForm is a SelectField. - Columns utilizing radio representation is typed
'rad'
(MASTER_coltypes[i] = 'rad'
), and the corresponding field in the SubForm is a RadioField.
MASTER_choicecols = [str choice_col0, str choice_col1, ...]
MASTER_choices = [
[ (str col0_choice0, str col0_display0),
(str col0_choice1, str col0_display1),
... ],
[ (str col1_choice0, str col1_display0),
(str col1_choice1, str col1_display1),
... ],
...
]
MASTER_radiocols = [str choice_col0, str choice_col1, ...]
MASTER_radios = [
[ (str col0_choice0, str col0_display0),
(str col0_choice1, str col0_display1),
... ],
[ (str col1_choice0, str col1_display0),
(str col1_choice1, str col1_display1),
... ],
...
]
An example can be seen in the code at the top of the article.
NOTE #1: Take care that MASTER_choicecols and MASTER_choices have the same length. Similarly for MASTER_radiocols and MASTER_radios.
NOTE #2: The SelectField and RadioField defined in the SubForm DOES NOT include the choices. (Again, see example at the top.)
Search and Fill
Since the in-line form of a table is programmatically generated, the search-fill function cannot wait until the designing step like CuneiForm's does. The search-fill function of an in-line form is defined in this step via the variable MASTER_schfill.
MASTER_schfill = {
str search_col0: [str search_spec0, str fill_spec0],
str search_col1: [str search_spec1, str fill_spec1],
...
}
# Example from Bank Account table
MASTER_schfill = {
"bank_code": ["ModalBank:code",
"bank_stid:stid,bank_name:name,bank_branch:branch"],
"acccode_code": ["ModalAccCode:code",
"acccode_name:name,acccode_stid:stid"]
}
NOTE: The formats of search_specX and fill_specX is similar to arguments search and fill in CuneiForm's render_blank macro.
Instant Calculation
Instant calculation function within in-line forms, or 'instacalc', allows a change in one form field to initiate a small calculation request to the server and update other affected fields based on the calculation result. It is specified in the variable MASTER_instacalc
of the CuneiTable.
(Refer to the dedicated sub-section in CuneiForm article for format and example.)
Auto-numbering Function
In-line forms with auto-numbering specifications work with CuneiFox core system to serve auto running numbers in a particular format (usually for document numbers). The specifications for this feature are embedded within MASTER_autorun
of the CuneiTable.
(Refer to the dedicated sub-section in CuneiForm article for format and example.)
Table with a Separate Form Modal
Sometimes, the entries have either too many columns or columns not suitable for display in the table format. In such cases, developers can use the full-form option. CuneiTable with an associated full-form is only defined with essential columns for a 'quick glance' view. The full form is shown in a pop-up modal for entry addition/edit.
A CuneiTable can be linked to a full-form via the class variable MASTER_fullform which takes the following format:
MASTER_fullform = [str module_code, str fullform_class_name,
str fullform_modal_header_text, str modal_size]
# Example from Product table
MASTER_fullform = ['cunei_iv', 'ProductFullForm', 'Product Information', 'xl']
- size dictates the modal size displayed on the client-side. It utilizes BootStrap 4's
'modal-<size>'
classes. Available choices are'sm'
,'md'
(corresponds to default modal size),'lg'
, and'xl'
.
NOTES on full-form class and macro:
- The CuneiForm class
fullform_class_name
must be found undermodule_code
in the filecuneifox/<module_code>/forms.py
orcuneifox/<module_code>/forms.pyc
. - The definition of the full-form class DOES NOT include the Submit-delete Field Set
- The Jinja2 macro for the full-form design must also be named
fullform_class_name
and must be found undermodule_code
in the filecuneifox/<module_code>/template/<module_code>/form_macro.html
. - Refer to the main CuneiForm article for more details on form definition and design. For information specific the full-form macros, refer to a dedicated sub-section below.
In-line Form with Expansion
Some tables contain just a tab too many columns, but not enough to warrant a fully-fledged separate form. In this case, CuneiTable allows its in-line form to have some fields drawn separately in an expansion modal. This behaviour is controlled by the variables MASTER_expand, MASTER_tbexpand, and MASTER_manualdraw.
MASTER_expand = {str trigger_field0: str expand_spec0,
str trigger_field1: str expand_spec1,
...}
MASTER_tbexpand = str expand_spec
MASTER_manualdraw = [str expand_field0, str expand_field1, ...]
# Example from the product table on the 'Product Delivery' page
MASTER_expand = {"product_code_mock":"BodyEx1:product_name"}
MASTER_tbexpand = "BodyEx1:product_name"
MASTER_manualdraw = ["product_code", "product_name", "desc", "manage_serial", "serial_nos"]
- trigger_field: The field with an Expand button
'<expand_modal_id>:<first_expand_field>'
attached when the form is triggered. - expand_spec: The modal and field to focus on once the Expand button is presses. (Shares the format with the argument expand in CuneiForm's render_blank macro.)
- expand_field: The field to be skipped during dynamic in-line form generation. Fields listed in MASTER_manualdraw must be put on the page manually.
Injections & Post-submission Logics
Some columns, while not stored directly in the database, are quite essential, or at least useful, to display on the client-side table. In CuneiFox's normal operation, whether it be a data fetch request or a display table update after a database commission, the server returns (representation of) entries from within the database. This ensures the client-side is shown the most updated data, but it also means that columns not in the database do not show up by default. Variables MASTER_preserve_across and MASTER_inject_func seek to better this behaviour.
Employing a similar routine, variable MASTER_post_submit_func allows additional logic to be run after a database commit from a CuneiTable.
MASTER_preserve_across
: (This feature is active AFTER SUBMISSION) A list of field names, present in the in-line form but not in the database, whose values are read from the form and reinjected into the data sent to client for table manipulation.MASTER_inject_func
: (This feature is active ON SINGLE-ENTRY FETCH) A list of functions (and their arguments) to run just before the fetched entry is sent to the client-side.MASTER_post_submit_func
: (This feature is active AFTER SUBMISSION) A list of functions (and their arguments) to run just after a database commit. This feature is useful both for additional logic run and to modify the returned entry (in the same vein as inject_func does for a fetch request).
MASTER_preserve_across = [str field_name0, str field_name1, ...]
MASTER_inject_func = {'func': <function_object>,
'args': <list_of_ordered_arguments>}
MASTER_post_submit_func = {'func': <function_object>,
'args': <list_of_ordered_arguments>}
# Example from (former) tax ID table
MASTER_preserve_across = ["bcount"]
# Example from product group table
MASTER_inject_func = {"func":defvat_inject, "args":[]}
# Example from account book table
MASTER_post_submit_func = {"func":accbook_to_docseries, "args":[]}
NOTE #1: preserve_across feature is automatically assumed for columns covered by CuneiModel's Cross-table references. There is no need to list such columns in MASTER_preserve_across.
NOTE #2: At the time of writing, CuneiTable's injections & post-submission logics are handled automatically only on the #Shortcut Route for Single-table Page & Search Table.
Other Table Definition Variables
Other notable MASTER variables that can be set upon form definition include:
MASTER_firstonly
: A list of field names that are only active (editable) for a new entry, but inactive (not editable) when editing an old entry.MASTER_pseudohides
: A list of field names for which the corresponding fields are not rendered on form triggering.MASTER_delconfirm
: The specification for the delete confirmation modal. This value shares the format with the argument confirm_first in CuneiForm's render_blank macro. The default value is['This will delete...', 'code']
MASTER_firstonly = [str field_name0, str field_name1, ...]
MASTER_pseudohides = [str field_name0, str field_name1, ...]
MASTER_delconfirm = [str confirm_modal_header, str field_name_to_confirm]
# Example from account code table
MASTER_firstonly = ["stid"]
# Example from journal setting table
MASTER_pseudohides = ["book", "colspec"]
# Example from Accounting Journal's VAT table
MASTER_delconfirm = ["This will delete...", "taxdoc"]
Initiate
CuneiTable class has its own __init__
function.
__init__(self, prefix="", **kwargs)
Parameters |
|
The rough step-by-step of a CuneiTable's initiation is as follows:
- Assign the following MASTER variables to corresponding attributes of the CuneiTable instance (if the attributes are not specified otherwise):
- Modify the full-form class with standard field set, initiate the full-form, and modify the form instance's attributes (where applicable).
- Modify the in-line SubForm class with standard field set, initiate the in-line form, and modify the form instance's attributes.
- Assign the choice and radio MASTER variables to corresponding attributes of the CuneiTable instance (if the attributes are not specified otherwise). Then, use the attributes to modify the choices of the in-line form fields.
- Add values corresponding to the standard column set to the 3 main MASTERs.
Standard Column Set
CuneiTable requires a few standard columns in order to function properly. These columns need not be defined explicitly, but are programmatically generated and integrated into all CuneiTable instances. The 4 standard columns include:
- id, submit, is_del: These columns correspond to the #Submit-delete Field Set of the corresponding in-line form or full-form. Developers can also choose to explicitly define these columns in the class definition (especially the id column) if they desire.
- The multi-selection column: This column is only created for a table with multi-selection enabled. It is displayed as the leftmost column of the table. (See the note on multi attribute below.)
Column Sizes & Post-init Modification
For easier development, column sizes are defined (via MASTER_colsizes) in relative sizes. However, those values are not used directly in the client-side render. They would have to converted to percentage values first via an internal function. While developers rarely need to tamper with column sizes after class definition, there are cases where tables are reused for many pages and with some columns hidden (in other words, resized to 0) in some of its incarnation.
Column resizing, post-initiation, is done by running 2 function consecutively: assign_csize
and tune_cols
.
assign_csize(self, cname, csize)
Parameters |
|
Notes | At this stage, the CuneiTable instance have alrady gone through one round of size tuning. Hence, the value csize should be set to the new relative (100-based) basis. |
tune_cols(self, skip_multicheck=False)
Parameters |
|
Notes on Keyword Arguments
The following sub-sections introduce notable keyword arguments. Other keywords not detailed here are also welcome during CuneiTable initiation. Unless explicitly specified, all keyword arguments can be accessed post-initiation as attributes of the created CuneiTable instance.
MASTER-adjacents
Back to the #Define section, we are introduced to a number of MASTER variables. Those variables set at table definition act as the default values for each table type. However, developers can feed an overriding value that applies only to the CuneiTable instance being initiated via a corresponding non-master keyword (e.g. use keyword instacalc to override the class's MASTER_instacalc).
The option to modify object-specific values after initiation is also available. However, since value packing and manipulation occurs during initiation, some details should be noted:
- colsizes, colnames, expand, tbexpand, manualdraw, del_confirm (corresponds to MASTER_delconfirm), preserve_across, post_submit_func, inject_func, and pseudohides are normal table attributes and directly take on the values of their MASTER counterparts. They can easily be accessed and modified.
- radiocols and choicecols take on the values of their MASTER counterparts. These 2 attributes work closely with the next item on this list.
- radios and choices take on the values of their MASTER counterparts. These attributes are used to generate a translation map on the client-side to aid value display. CuneiTable's initiation routine also includes assigning these values as the choices attributes of corresponding in-line form (including expansion) fields as well.
- schfill takes on the value of MASTER_schfill. This attribute applies only to in-line form (dynamically-generated) fields. Fields under manualdraw must have equivalent values specified during the form designing phase.
The following attributes do not allow value feeding during initiation phase. However, they can be modified after the fact if needed, so it is fit to discuss them here. (SubForm and FullForm referenced here can be accessed via appropriate CuneiTable attributes. See #Form References sub-section.)
- SubForm.firstonly and FullForm.firstonly: For an in-line form, the form attribute is copied directly from MASTER_firstonly. For a full-form, members from MASTER_firstonly are appended to what the form originally has by itself.
- SubForm.autorun and FullForm.autorun: For an in-line form, the form attribute is copied directly from MASTER_autorun. For a full-form, members from MASTER_autorun are appended to what the form originally has by itself.
- SubForm.instacalc takes the value of MASTER_instacalc. Its post-init format can be found in the CuneiForm article. Note that MASTER_instacalc only affect in-line form fields.
- SubForm.coltypes is taken (and modified to accommodate the standard column set) from MASTER_coltypes. The initation routine also includes extracting appropriate values from this list to set the special_type field attributes for in-line form as well.
Know Thy Self
Sequence and Columns
- seq and cnames attributes of a CuneiTable are copied to its in-line form. These attributes do not support value feeding during initiation because they are highly involved in the process. In fact, it is NOT RECOMMENDED to trifle with them at all. Their functions can be found in the corresponding section on the CuneiForm page.
- content_width (str): The width of the table itself (not the bounding element of the table) on the client-side display. The value can be anything interpretable as CSS size.
Form References
Getting Data
Sending Data
Both in-line form and full-form submit in a non-redirecting fashion by CuneiFox default. So, the only important attribute regarding form submission via a CuneiTable is:
- post_route (url_for_string: defaults to
False
): Route to send a submit request.
In rare cases where redirection is needed, developers can either modify the appropriate attributes of the in-line form and/or full-form can be modified (see CuneiForm#Sending Data), OR package a redirect or reload command with the submission response (see CuneiForm#Non-redirecting Form).