-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
create table technical design #71
Changes from all commits
76d7770
78b14d4
b06a817
b2271ed
abdb608
ab4841a
1deac9e
e97fe7b
f7572d6
6d8f151
7f5e8f2
a5f5061
5364c53
84fab89
741b230
eae4385
2f43a55
29ab109
2a755fa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
--- | ||
name: Spec | ||
menu: Table | ||
CaffeinatedAllie marked this conversation as resolved.
Show resolved
Hide resolved
|
||
route: /table-spec | ||
--- | ||
|
||
# Technical Design - Espressive Table | ||
|
||
# Current implementations | ||
|
||
As of `goldengirls` release, we use tables in the following applications: | ||
|
||
Barista: | ||
|
||
- Admin | ||
- Service Department | ||
- Service Teams | ||
- Barista FAQs | ||
- Users | ||
- Locations | ||
|
||
Caffeine | ||
|
||
- Configuration | ||
- Entities | ||
- Localization | ||
- Training | ||
- Variables | ||
lordpixel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- Status | ||
- Doppio | ||
|
||
## Features in tables | ||
|
||
The features in those tables vary from one implementation to another, but the general idea is to present the data in a tabular way, ussually also providing the means for data persistance. The aggregated features list is the following: | ||
|
||
**Item creation**: | ||
Some tables allow the user to create a new entry in the table. Adding an empty row. | ||
|
||
**Inline edition**: | ||
Some tables allow the user to edit the data, replacing the display representation with some JSX that allows the mutation of the data. | ||
|
||
**Item deletion**: | ||
Some entities in our API allow item deletion, some others don't. The `delete` functionality must be `opt-in`. | ||
|
||
**Custom actions**: | ||
In most implementations, tables add a trailing column to each row. This row can display `action buttons`, which can be mapped to corresponding actions over the entire row. i.e. edit, delete, cancel, etc. | ||
lordpixel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
All of the features mentioned above must be `opt-in`. | ||
|
||
## Data representation / mutation | ||
|
||
The way each cell represents the data for either display or edit purposes not only depends on the data type but also on business logic, in most cases, values are easily coerced to string for display purposes and updates are easily achieved via a controlled input component. The rest of scenarios require a more complex implementation, e.g. the `employee` field in the `Users` table from `Barista Admin` which under the carpet is a single `eid`, but the representation of that cell is an avatar with the user name it points to, although it could be any other representation, specially when editing the value. | ||
|
||
Note: The updates made to any row would be notified upstream via `events` so the parent component is able to persist those changes. The means by which the table enables data mutation are to be provided by the developer in the form of `triggers`, the table doesn't provide such means. | ||
|
||
# Proposal | ||
|
||
Much thought has been put to the proposal described in this section, our goal is to create a table that can support all of our current use cases while at the same time being abstract enough to support future ones. We are not inventing the wheel here, there are great open source libraries like `react-table`. The problem with those libraries is that they are bloated with things we don't need either because we already abstracted such functionality out to other components or we simply don't need it. | ||
|
||
## Espressive CRUD Table | ||
|
||
Given the nature of our actual tables and the operations we need to perform on the data entities, a CRUD Table starts to make sense. A kind of table that not only displays data in a nice tabular way, but also allow for a richier interaction with the data. | ||
|
||
It is true that CRUD operations are needed in less scenarios, so the CRUD feature must be easily enabled and must not interfere with the regular table logic. | ||
|
||
## Props | ||
|
||
 | ||
|
||
### Events | ||
|
||
In order to support CRUD operations, we must define a mechanism to communicate the parent any changes to the data. | ||
|
||
- onCreate | ||
- onUpdate | ||
- onDelete | ||
- onTrigger | ||
|
||
Please note that the names could have been something like `onItemCreate` for semantics, but let's remember that in the future we plan to support selection and custom actions on multiple items. Our proposal is to keep these as abstract as possible. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good stuff. I suspect that this pattern is going to be our bread and butter for a lot of these components. After all, there are all kinds of scenarios on the implementation end where a developer will want to get a snapshot of our component's data when something happens outside of it. Based on this... we should be thinking about this pattern overall. How do we keep the choices we make here as consistent as possible? Let's take some extra time really focusing on the semantics of the CRUD operations we expose, what their signatures look like, and what parameters they return. They should be consistent across all components when we reach for a onCreate function or onUpdate function. Also... should we have a separate onDelete, onUpdate and onCreate function? What if we just have an onUpdate function that returns a
I will create a MDX file for us to make some notes about components and CRUD operations in Cascara in general so we can start putting some of our decisions there. That way once we start deciding on how we want some of these things to look and feel, we can keep that up to date. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @brianespinosa the definitions for the rest of the CRUD events are below. |
||
|
||
| Event | Signature | Description | | ||
| --------- | ------------------------------------------------- | --------------------------------------------------------------- | | ||
| onCreate | `(Object: newItem) => {}` | Fired when the User saves a new item | | ||
| onUpdate | `(Array[Object]: updatedItems) => {}` | Fired when one or more rows have been updated by the User | | ||
| onDelete | `(Array[String]: selectedItems) => {}` | Fired when one or more rows have been deleted by the User | | ||
| onTrigger | `(String: actionType, Array[String]: data) => {}` | Fired when a custom action has been applied to one or more rows | | ||
|
||
### Config | ||
|
||
There will be use cases where features like multi-selection, CRUD, custom actions, etc. won't be required at all, they must be disabled by thefault but easily activated. It makes sense to have boolean props that controll such features. | ||
|
||
Another important aspect of configuration is the definition of columns, hence a complete section is devoted to it. | ||
|
||
| Name | Type | default | Description | | ||
| ------------------ | ------------- | ------- | -------------------------------------------------- | | ||
| Bulk (enhancement) | Boolean | `FALSE` | If true, activates the bulk mode (multi-select) | | ||
| Columns | Array[Object] | `[]` | Holds the definitions for each column in the table | | ||
| Create | Boolean | `FALSE` | If true, activates the creation of new items | | ||
| Delete | Boolean | `FALSE` | If true, activates the deletion of items | | ||
| Update | Boolean | `FALSE` | If true, activates the edit mode | | ||
|
||
### Triggers | ||
|
||
Custom actions are present in most tables, they are an important aspect of all applications. The nature of the actions depends on the entity they are applied to, hence, an abstract way of defining custom actions is required. | ||
|
||
| Attribute | Type | default | Description | | ||
| --------- | -------- | ------------ | ----------------------------------------------------------- | | ||
| id | String | `''` | The id of the action, usually the name. | | ||
| callback | Function | `noop` | The function to be called when the action button is clicked | | ||
| trigger | ANY | `<Button />` | The element that will trigger the action | | ||
lordpixel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
### Data | ||
|
||
The data passed to the table for rendering purposes. | ||
|
||
| Name | Type | default | Description | | ||
| ---- | ------------- | ------- | --------------------------------------------- | | ||
| data | Array[Object] | `[]` | the tabular data to be displayed by the table | | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if there are some consistent things we could at least make sure are present in these data objects. I guess the only thing for sure that we would want to make sure of is An Not sure if we should necessarily address that here. Also, like the pattern of CRUD operations, I think that a |
||
|
||
### Columns | ||
|
||
The definition of columns depends on the data, we must make sure we have a well-defined set of data types to allow display and mutation for each one. | ||
|
||
| Attribute | Type | default | Description | | ||
| ---------- | ---------------------------------------------------------------------- | ---------- | -------------------------------------------------------- | | ||
| attribute | String | `null` | The name of the entity attribute that maps to the column | | ||
| isEditable | Boolean | `FALSE` | Specifies if the cells are editable | | ||
| label | String | `''` | Label text to display with this attribute | | ||
| type | Enum[`boolean`, `date`, `image`, `link`, `number`, `string`, `render`] | `'string'` | Specifies the type of data for the column | | ||
|
||
### Data types | ||
|
||
The data types this table can handle are the following: | ||
|
||
For display puposes: `boolean`, `date`, `image`, `link`, `number`, `string` and `render`. The `render` type being a custom JSX. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should figure out how to identify which of these is part of MVP and which is future. Also, we need to figure out what these little guys are called. They will be used in a reusable manner all over Cascara. Basically they are like display atoms or something. And they will have an editing experience as well.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @brianespinosa, I double-checked the apps to see which atoms are to be included in the MVP. Display
Edit
The atoms we use for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For "edit" the experience needs to be more simple for MVP. I think for boolean we can only do a default html checkbox. For date, we should show an input date time field, not our own date picker. Basically the edit experience for MVP is going to be: whatever is available in html and what do browser vendors provide natively. We will absolutely have other options though in the future:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok sounds good! Thanks for reminding me about HTML5, the mobile functionality aspect is very important. I mentioned the switch instead of checkbox because wee have tables that implement it. At the end of the day we can style an HTML5 checkbox to make it look/behave as a switch. I have some ideas on that matter that I want to explore and run by @CaffeinatedAllie. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep. I think with these atoms, there are also use cases where we will want a checkbox too. Eventually someone could decide which control they want to show for their boolean. Does a checkbox, a switch, an enum select make the most sense? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, they completely make sense. The enum select will have the You just uncovered a track we can start to follow in terms of abstraction, looking forward to it! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will start typing these ideas into code soon, these kind of convos make really think about implementation! 🙌 |
||
|
||
For mutation purposes, the implementation will support `select`, `input`, `boolean switch`, `date / time pickers`, `lookup select`. With the ability to expand to more types. | ||
|
||
## Context | ||
|
||
All the internal logic will be hosted in a Context. The definition is WIP. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, I can tell this is specific to React context. 👍🏽 Moving forward, any time we are referring to something that is part of React as part of the API, or any other tool as part of the API, we should figure out a consistent way of calling that out. We have a lot of terms in our ecosystem that have special meaning which we want to be clear on. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yup, that's React Context. I will make it clear throught the document. |
||
|
||
## The complete JSX picture | ||
|
||
``` | ||
<Table | ||
// config | ||
bulk | ||
create | ||
delete | ||
update | ||
|
||
coluns=[{}] | ||
|
||
// events | ||
onCreate={this.handleNewItem} | ||
onDelete={this.handleItemDelete} | ||
onUpdate={this.handleItemUpdate} | ||
onTrigger={this.handleTriggers} | ||
|
||
// triggers | ||
triggers={[ | ||
{ id: 'cancel', ...additionalConfig }, | ||
{ id: 'view', ...additionalConfig }, | ||
]} | ||
|
||
// data | ||
data={[{}]} | ||
/> | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is to make sure we are trying to parse MDX for actual MDX files and not a directory.