-
Notifications
You must be signed in to change notification settings - Fork 7
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
MARKET-1466 Cascade Select #184
Open
StasivPavlo
wants to merge
13
commits into
main
Choose a base branch
from
bl-cascadeSelect-component
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
fba6398
add component Cascade Select
StasivPavlo c374578
finished component, added README.md and preview.html
StasivPavlo 8314f6e
code style fixed
StasivPavlo 3bf0e3e
minor fixes
StasivPavlo 022fb51
Merge remote-tracking branch 'origin/bl-cascadeSelect-component' into…
StasivPavlo 95a4a7d
minor and code style fixes
StasivPavlo c1ffbc2
added action get and set for Code, Cascade
StasivPavlo 17372be
added component.el
StasivPavlo 998d639
minor fixes
StasivPavlo adbe54c
minor fixes
StasivPavlo b5e1786
added actions to the component.json and README.md
StasivPavlo dc27d5d
Merge branch 'main' into bl-cascadeSelect-component
StasivPavlo 557a11b
renamed directory
StasivPavlo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# Cascade Select | ||
|
||
Cascade Select is a component of Backendless UI-Builder designer. This allows you to select a value from a nested structure of options. | ||
|
||
## Properties | ||
|
||
| Property | Type | Default Value | Logic | Data Binding | UI Setting | Description | | ||
|-------------------|---------|---------------------|-----------------------------|--------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||
| Cascade | JSON | | Cascade Logic | YES | YES | Allows determinate an array of select items to display as the available options. Watch [Codeless Examples](#Examples). Signature of polygon: `[{name, code, ?children}]` | | ||
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. code -> value |
||
| Placeholder | String | | Placeholder Logic | YES | YES | Allows determinate placeholder for input | | ||
|
||
## Events | ||
|
||
| Name | Triggers | Context Blocks | | ||
|---------------|-------------------------------|--------------------------------------------------------------| | ||
| On Click Item | when the user select the item | Item: `{name: String, code: String, levelOfNesting: Number}` | | ||
|
||
## Action | ||
|
||
| Action | Inputs | Return | | ||
|---------------|------------------|-----------------------------| | ||
| Get Select in | | Object: of a select item | | ||
| Set Cascade | cascade: `Array` | | | ||
| Get Cascade | | Array: of s cascade | | ||
| Set Code | code: `String` | | | ||
| Get Code | | String: code of select item | | ||
|
||
## <a name="Examples"></a> Codeless Examples | ||
|
||
Addition of cascade data | ||
|
||
![](example-images/cascade_example.jpg) | ||
|
||
<details> | ||
<summary>Try yourself</summary> | ||
|
||
``` | ||
<block xmlns="http://www.w3.org/1999/xhtml" type="lists_create_with" id="I6`{YbX`1w)ZrZA[n(3l" x="-94.53923425078003" y="88.92089374100392"><mutation items="2"></mutation><value name="ADD0"><block type="create_object" id="hd^`S({p+5%(tCzQMIkl"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item><item id="property" prop-name="children"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id="Rmz=y,*(iJ0^*7tqt^wN"><field name="TEXT">Australia</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="73(!S~9Bj8[(1dd.hOG%"><field name="TEXT">AU</field></block></value><value name="create_object_mutator_container_properties_stack_property2"><block type="lists_create_with" id="+^[pE!*BrEq@/~$ZXJDM"><mutation items="2"></mutation><value name="ADD0"><block type="create_object" id="ely].XX{?.SFw}g*Ux$F"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item><item id="property" prop-name="children"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id="0,Ub7#U7iP^Uc;F1W,l%"><field name="TEXT">New South Wales</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="w#9]c/AL5qytPDCGEGh^"><field name="TEXT">AU-NSW</field></block></value><value name="create_object_mutator_container_properties_stack_property2"><block type="lists_create_with" id="NcaOOw}XzebfYg[$#]*V"><mutation items="3"></mutation><value name="ADD0"><block type="create_object" id="=@e``]rkt/IwmHZaxEGU"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id="e(%`Bzh$xiJ9{xFo2YL/"><field name="TEXT">Sydney</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="[.3Q:STX@sn9Lw}pm7Qc"><field name="TEXT">AU-NSW-SY</field></block></value></block></value><value name="ADD1"><block type="create_object" id="dTF-V$w2/}%bGhSyA%]Q"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id="0WOJ4K22**Az9=mscXx7"><field name="TEXT">Newcastle</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="^D)=+TRJD8Hbb(X%qAy."><field name="TEXT">AU-NSW-NC</field></block></value></block></value><value name="ADD2"><block type="create_object" id="ZAL1i-YAD!U*bPcteuR!"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id="101HuiZBCvUT)Q=k;c7O"><field name="TEXT">Wollongong</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="II{6/P]UldmqR84w=#yo"><field name="TEXT">AU-NSW-WG</field></block></value></block></value></block></value></block></value><value name="ADD1"><block type="create_object" id="23VyPHa2^%a{BnrD;:oc"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item><item id="property" prop-name="children"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id="qdN:ohQ^xc{~Rsn:GAq+"><field name="TEXT">Queensland</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="UFX@h3$}X52c}@S^*p/^"><field name="TEXT">AU-QS</field></block></value><value name="create_object_mutator_container_properties_stack_property2"><block type="lists_create_with" id="@=LxHd02i?4?t+rW|64h"><mutation items="2"></mutation><value name="ADD0"><block type="create_object" id="%wf4cFQJ/qGl{7/Il2A$"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id=".Tn=|{GrFAU]w[=21lH."><field name="TEXT">Brisbane</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="e`w,YXw1(ceOTdI2j9+L"><field name="TEXT">AU-QS-BB</field></block></value></block></value><value name="ADD1"><block type="create_object" id="%rbhI}Sb!@Vue942V_W}"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id="x4~`U{VoDZ3gMG`i3-Fg"><field name="TEXT">Townsville</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="v{y{ntd-%*4fjlFH4)=!"><field name="TEXT">AU-QS-TS</field></block></value></block></value></block></value></block></value></block></value></block></value><value name="ADD1"><block type="create_object" id="st!J)Cx*,C_Xx4E)5,,|"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item><item id="property" prop-name="children"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id="(*uAjQ7(V_NLb#`mc)!s"><field name="TEXT">Canada</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="JZrB.YadV5v/APu_6/xL"><field name="TEXT">CA</field></block></value><value name="create_object_mutator_container_properties_stack_property2"><block type="lists_create_with" id="It-{1g[_kl})XaTbVnlK"><mutation items="2"></mutation><value name="ADD0"><block type="create_object" id="[email protected]+b]ipJ3dnDD+"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item><item id="property" prop-name="children"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id="G7j*jnSN(Annx89J{Ko:"><field name="TEXT">Quebec</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="w[O4hm|+LN4`3kHsfo^v"><field name="TEXT">CA-QB</field></block></value><value name="create_object_mutator_container_properties_stack_property2"><block type="lists_create_with" id="h8Aa4cJAZ+Z2bTu;v=@j"><mutation items="2"></mutation><value name="ADD0"><block type="create_object" id="eKI@M]|TJAL_3O@|tV7}"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id="}l+-hZaLgz)z,SSO~yE`"><field name="TEXT">Montreal</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="lpCB5?#F[vP_b{!`yDGK"><field name="TEXT">CA-QB-MR</field></block></value></block></value><value name="ADD1"><block type="create_object" id="^LaaQXj.d}=ii[.0=`~;"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id="m0L`+S|g$=qv~fKFe(WF"><field name="TEXT">Quebec City</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="A;RO8hooP(x*Feh}~ohR"><field name="TEXT">CA-QB-CBC</field></block></value></block></value></block></value></block></value><value name="ADD1"><block type="create_object" id="zlA_eq+Dyde5(~QORUv0"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item><item id="property" prop-name="children"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id="Yt7Xd-sMIFsp]0DrG*~D"><field name="TEXT">Ontario</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="~8l2Q5MC/Ko3KR:EJeEs"><field name="TEXT">CA-OT</field></block></value><value name="create_object_mutator_container_properties_stack_property2"><block type="lists_create_with" id="_GWtd^*`0F1VY`aNycML"><mutation items="2"></mutation><value name="ADD0"><block type="create_object" id="RO2Sy[E4,FQU#z$IuFvx"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id="@P`$ZS$j6tVBtX_7*sqz"><field name="TEXT">Ottawa</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="%AxPNTGKb#_)r{welh5,"><field name="TEXT">CA-OT-OW</field></block></value></block></value><value name="ADD1"><block type="create_object" id="d|X]SW;eH:GO]Hi9ff(H"><mutation><properties><item id="property" prop-name="name"></item><item id="property" prop-name="code"></item></properties></mutation><value name="create_object_mutator_container_properties_stack_property0"><block type="text" id="yxz9yUj@6RM^$caT*;Y?"><field name="TEXT">Toronto</field></block></value><value name="create_object_mutator_container_properties_stack_property1"><block type="text" id="[Xw5938k[M2kk;lD_#Q5"><field name="TEXT">CA-OT-TR</field></block></value></block></value></block></value></block></value></block></value></block></value></block> | ||
``` | ||
</details> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
{ | ||
"id": "c_4709a015328b307e652d915fc3f36fb7", | ||
"name": "Cascade Select", | ||
"description": "Cascade Select is a component to select a value from a nested structure of options.", | ||
"showInToolbox": true, | ||
"faIcon": "check-double", | ||
"mainJS": "dist/index.js", | ||
"type": "custom", | ||
"category": "Custom Components", | ||
"properties": [ | ||
{ | ||
"type": "json", | ||
"name": "cascade", | ||
"label": "Cascade", | ||
"showInSettings": true, | ||
"hasLogicHandler": true, | ||
"handlerId": "cascadeLogic", | ||
"handlerLabel": "Cascade Logic", | ||
"dataBinding": true, | ||
"handlerDescription": "This is a handler for the logic to determine an array of select items to display as the available options." | ||
}, | ||
{ | ||
"type": "text", | ||
"name": "placeholder", | ||
"label": "Placeholder", | ||
"showInSettings": true, | ||
"hasLogicHandler": true, | ||
"handlerId": "placeholderLogic", | ||
"handlerLabel": "Placeholder Logic", | ||
"dataBinding": true, | ||
"handlerDescription": "This is a handler for the logic to determine the default text to display when no option is selected." | ||
} | ||
], | ||
"eventHandlers": [ | ||
{ | ||
"name": "onClickItem", | ||
"label": "On Click Item", | ||
"contextBlocks": [ | ||
{ | ||
"id": "item", | ||
"label": "Item" | ||
} | ||
], | ||
"handlerDescription": "This event is triggered when user select item" | ||
} | ||
], | ||
"actions": [ | ||
{ | ||
"id": "getSelected", | ||
"label": "Get Selected in", | ||
"hasReturn": true | ||
}, | ||
{ | ||
"id": "setCascade", | ||
"label": "Set Cascade", | ||
"inputs": [ | ||
{ | ||
"id": "cascade", | ||
"label": "Cascade" | ||
} | ||
] | ||
}, | ||
{ | ||
"id": "getCascade", | ||
"label": "Get Cascade", | ||
"hasReturn": true | ||
}, | ||
{ | ||
"id": "setCode", | ||
"label": "Set Code", | ||
"inputs": [ | ||
{ | ||
"id": "code", | ||
"label": "Code" | ||
} | ||
] | ||
}, | ||
{ | ||
"id": "getCode", | ||
"label": "Get Code", | ||
"hasReturn": true | ||
} | ||
] | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<div data-module-type="system" data-module-id="block" data-display data-uid="97c1e475f636c6292fddcff60a990462" style="display:flex;flex-shrink:0;min-width:100px;border:2px solid #aaaaaa;flex-direction:row;justify-content:space-between;align-items:center;padding:10px 10px 10px 10px;border-radius:6px 6px 6px 6px;"><span data-content="Cascade Select" data-module-type="system" data-module-id="text" data-display data-uid="398503af28abc33291c6092d9661cbe5" class="bl-text" style="color:#aaaaaa;"></span><i data-icon="arrow_forward_ios" data-size="small" data-module-type="system" data-module-id="icon" data-display data-uid="57c3cba667be0bfe1fdeafc5362aa967" style="color:#aaaaaa;"></i></div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
export const validate = (cascade, setItemsCascade, setParentItems, setItems) => { | ||
const { isCircular, cycleLocation } = analyzeCircularDependencies(cascade); | ||
|
||
if (isCircular) { | ||
throw new Error('cascade have cycling object in ' + cycleLocation); | ||
} | ||
|
||
if (cascade) { | ||
setItemsCascade(prepareCascade(cascade, setParentItems, setItems)); | ||
} | ||
}; | ||
|
||
function analyzeCircularDependencies(obj) { | ||
const keys = []; | ||
const stack = []; | ||
const stackSet = new Set(); | ||
let isCircular = false; | ||
let cycleLocation; | ||
|
||
function detectCircular(obj, key) { | ||
if (obj && typeof obj != 'object') { | ||
return; | ||
} | ||
|
||
if (stackSet.has(obj)) { | ||
cycleLocation = keys.join('.') + '.' + key; | ||
isCircular = true; | ||
|
||
return; | ||
} | ||
|
||
keys.push(key); | ||
stack.push(obj); | ||
stackSet.add(obj); | ||
|
||
for (const k in obj) { | ||
if (Object.prototype.hasOwnProperty.call(obj, k)) { | ||
detectCircular(obj[k], k); | ||
} | ||
} | ||
|
||
keys.pop(); | ||
stack.pop(); | ||
stackSet.delete(obj); | ||
} | ||
|
||
detectCircular(obj, 'obj'); | ||
|
||
return { isCircular, cycleLocation }; | ||
} | ||
|
||
const prepareCascade = (cascade, setParentItems, setItems) => { | ||
let levelOfNesting = 0; | ||
const parentItems = []; | ||
const items = []; | ||
|
||
const prepare = cascade => { | ||
const validCascade = cascade.map(item => { | ||
let validItem = { ...item, levelOfNesting }; | ||
|
||
if (item.children) { | ||
levelOfNesting++; | ||
validItem = { | ||
...validItem, | ||
children: prepare(item.children), | ||
}; | ||
|
||
parentItems.push({ code: item.code, isOpen: false, levelOfNesting }); | ||
} else { | ||
items.push(validItem); | ||
} | ||
|
||
return validItem; | ||
}); | ||
|
||
levelOfNesting--; | ||
|
||
return validCascade; | ||
}; | ||
|
||
const preparedCascade = prepare(cascade); | ||
|
||
setParentItems(getNestedItems(parentItems, levelOfNesting)); | ||
setItems(items); | ||
|
||
return preparedCascade; | ||
}; | ||
|
||
const getNestedItems = (items, levelOfNesting) => { | ||
const groupParentItems = []; | ||
|
||
for (let i = 0; i <= -levelOfNesting; i++) { | ||
groupParentItems.push(items.filter(({ levelOfNesting }) => levelOfNesting === i)); | ||
} | ||
|
||
return groupParentItems; | ||
}; | ||
|
||
export const openCascade = (state, item) => { | ||
const currentParentItems = [...state]; | ||
const { code, levelOfNesting } = item; | ||
|
||
for (let i = 0; i < currentParentItems[levelOfNesting].length; i++) { | ||
const { code: parentItemCode, isOpen } = currentParentItems[levelOfNesting][i]; | ||
|
||
currentParentItems[levelOfNesting][i].isOpen = parentItemCode === code ? !isOpen : false; | ||
} | ||
|
||
return currentParentItems; | ||
}; | ||
|
||
export const findParentItem = (parentItems, item) => { | ||
const { levelOfNesting, code } = item; | ||
|
||
return parentItems[levelOfNesting].find(item => item.code === code); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { useCallback, useEffect, useState } from 'react'; | ||
|
||
import { openCascade, validate } from './helpers'; | ||
import { Cascade, CollapseButtonIcon } from './subcomponent'; | ||
|
||
const { cn } = BackendlessUI.CSSUtils; | ||
|
||
export default function CascadeSelect({ component, eventHandlers, elRef }) { | ||
const { display, classList, style, cascade, placeholder } = component; | ||
const { onClickItem } = eventHandlers; | ||
|
||
const [itemsCascade, setItemsCascade] = useState(); | ||
const [parentItems, setParentItems] = useState([]); | ||
const [items, setItems] = useState([]); | ||
const [selected, setSelected] = useState({ name: placeholder }); | ||
const [isOpen, setIsOpen] = useState(false); | ||
|
||
useEffect(() => { | ||
component.setCascade(cascade); | ||
}, [cascade]); | ||
|
||
const openCascadeHandler = useCallback(item => { | ||
setParentItems(state => openCascade(state, item)); | ||
}, []); | ||
|
||
const openItemHandler = useCallback(item => { | ||
setSelected(item); | ||
setIsOpen(false); | ||
|
||
onClickItem({ item }); | ||
}, []); | ||
|
||
const onClickInput = () => setIsOpen(state => !state); | ||
|
||
component.getSelected = () => selected; | ||
|
||
component.setCode = code => setSelected(state => items.find(item => item.code === code) || state); | ||
component.getCode = () => selected.code || ''; | ||
|
||
component.getCascade = () => itemsCascade; | ||
component.setCascade = cascade => validate(cascade, setItemsCascade, setParentItems, setItems); | ||
|
||
if (!display) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<div ref={ elRef } className={ cn('bl-cascade-select', classList) } style={ style }> | ||
<div | ||
className={ cn('cascade-select__input', { 'cascade-select__input--selected': selected.code }) } | ||
onClick={ onClickInput }> | ||
<span>{ selected.name }</span> | ||
<CollapseButtonIcon/> | ||
</div> | ||
<Cascade | ||
isOpen={ isOpen } | ||
selected={ selected } | ||
itemsCascade={ itemsCascade } | ||
parentItems={ parentItems } | ||
openCascadeHandler={ openCascadeHandler } | ||
openItemHandler={ openItemHandler } | ||
/> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
name -> label