-
Notifications
You must be signed in to change notification settings - Fork 6
Jhork/custom select from #130
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
Conversation
…ork/custom-select-from
Codecov Report
@@ Coverage Diff @@
## feature/custom-select #130 +/- ##
=========================================================
+ Coverage 87.96% 88.11% +0.14%
=========================================================
Files 47 47
Lines 1612 1666 +54
Branches 365 380 +15
=========================================================
+ Hits 1418 1468 +50
- Misses 192 196 +4
Partials 2 2
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
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.
Some of the behavior described in the PR comments may be hard to envision so if anyone wants videos I can make them.
I think a lot of this work will set us up to use this component for ODER BY and WHERE, hopefully with only changes needed in the parent components from here until we had multi -select support
| --soql-label-container-width: 80px; | ||
| --soql-selection-container-width: 400px; |
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.
Now these names better reflect how the values are used.
| width: var(--soql-selection-container-width); | ||
| min-height: 100px; | ||
| max-height: 300px; |
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 will dictate the dimensions of the options menu when visible. I was not sure how tall to make it. I did see some feedback in the issues of the tooling repo that they wish they could see more fields at one time. So maybe we could make it taller if need be?
| /* | ||
| During testing the getter for the displayValue() is called once | ||
| & before the renderedCallback that caches the inputSelectEl. | ||
| The only way I have been able to trigger another render of the component | ||
| is to click the search bar. | ||
| */ |
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.
I might want to post a question to the LWC framework channel asking about where the getters fit into the lifecycle of the component. I'm am surprised to see the getter called before the rendered callback and that an element is not in the DOM when we query for it in the renderedCallback()
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.
For now I can do a click event to get everything in place for the test but its not ideal.
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.
I wonder if the gitter is called during the render process. And then when it's finished rendering, we get the renderedCallback()
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.
I could see that. Does that mean that we are not using the right pattern to capture or access elements in the DOM between the getter and rendered callback? Something to consider.
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.
I don't know if there's other options. besides we introduce an isRendered boolean and then check for that everywhere. that could also be messy. i think it's just something we have to deal with.
| }); | ||
|
|
||
| describe('Dropdown Arrow', () => { | ||
| it('should toggle the options menu when clicked, with directional arrow', () => { |
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.
I thought about breaking this up into 3 tests but found I repeating 90% of the code so I just combined it.
| /* | ||
| 1. If the user is typing, display the searchTerm | ||
| 2. If singleSelect | ||
| - display the selected value (default) | ||
| - if there is no searchTerm | ||
| & the input is in focus | ||
| & the input is empty | ||
| display the placeholder | ||
| */ | ||
| get displayValue(): string { | ||
| if (this.hasSearchTerm) { | ||
| return this.searchTerm; | ||
| } | ||
|
|
||
| if (this.isSingleSelect && this.selectInputEl) { | ||
| if (!this.selectInputIsFocused || this.selectInputEl.value.length) { | ||
| return this._value[0] || ''; | ||
| } | ||
| } | ||
|
|
||
| return ''; | ||
| } |
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 method is used to control what displayed in the search bar as the value. I need to control the display logic and the state of the component separately.
I found that getting the behavior I wanted was tricky, and this might be something that is just inherently not intuitive. Without || this.selectInputEl.value.length in line 69, when the user would delete the last character of the input then the selected value would immediately repopulate in the input instead of showing the placeholder.
|
|
||
| if (this.isSingleSelect) { | ||
| this._value = [optionValue]; | ||
| } else { | ||
| this._value = [...this._value, optionValue]; | ||
| } |
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 might need to change when we want to implement true multi selection but the intention is to maintain state in the component with having to read/write to the model.
| set selected(objectName: string) { | ||
| this._selectedObject = objectName ? [objectName] : []; |
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.
The custom select component accepts an array of selections so I needed to re package the values from the model.
| --soql-label-container-width: 80px; | ||
| --soql-selection-container-width: 400px; |
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.
I changed this now so that the dataView and the builder UI are in sync.
| get isSingleSelect() { | ||
| return !this.multiple; | ||
| } | ||
|
|
||
| get isMultipleSelect() { | ||
| return this.multiple; |
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.
I realized this api as it is might be a bit odd.
this.multiple is set as boolean value false in the component. However, because LWC won't let us use literals in the template multiple={true} we have to pass in a string multiple="true".
Unfortunately, as it stands, that means that I could put anything as the the string value and it would be coerssed as boolean true so multiple = ''false" passed in from parent to child is also true.
To fix this I would have to set the default value to string "false" and only work with string values "true" and "false"
get isSingleSelect() {
return this.multiple === "false" || this.multiple === undefined;
}Or it would depend on the parent to use a getter to pass a boolean value to the child
// in the parent
get isMultiple() {
return true;
}
// html
multiple={isMultiple}I do not like the option with a getter in the parent. Sicme we are the only ones using this component at the moment I can see leaving it as is for now. I also don't mind adding logic to check explicitly for strings "true" or "false" but it might be a but verbose for a simple check, idk.
Thoughts @dehru?
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.
Meh, it's currently just us using it. and messing that up would be just us using it wrong.
|
|
||
| .select__dropdown-arrow { | ||
| transform: rotate(180deg); | ||
| margin-right: 2px; |
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.
for some reason, I feel the arrow is uncomfortably close to the right. Just a tad. Not a change request, just stating a strange gut reaction.
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.
ya know I had it at 5px originally but I noticed it was further away from the standard element so I changed it to match. I also feel like its a little close but the other thought it that we may want more room once the component is smaller in the WHERE form.
| </template> | ||
| <template if:true={noResultsFound}> | ||
| <!-- i18n --> | ||
| <p class="option option--placeholder">No results found.</p> |
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.
placeholder is a loaded term. how 'bout option--empty or option--noresults
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.
I went with option--disabled to be more generalizable. That way if we use it for something else we don't have to change the class again.
| searchBar.focus(); | ||
| return Promise.resolve().then(() => { | ||
| const classList = Array.from(searchBar.classList); | ||
| expect(classList).toContain('select__input-placeholder--fadeout'); |
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.
It's weird to have css classname changes to cause failing tests. I had that case in my work this week. it's a valid test...not much we can do about it.
| return Promise.resolve() | ||
| .then(() => { | ||
| optionsWrapperClassList = Array.from(optionsWrapper.classList); | ||
| expect(optionsWrapperClassList).toContain('options--open'); |
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.
might think about making this a const since it's used thrice in this test case.
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.
Done. Thanks
| }) | ||
| .then(() => { | ||
| optionsWrapperClassList = Array.from(optionsWrapper.classList); | ||
| expect(optionsWrapperClassList).not.toContain('options--open'); |
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.
very nice
| /** CUSTOM SELECT API | ||
| * @attr multiple: string - Toggle single-select or multi-select behavior. | ||
| * NOTE --> Will be interpreted as true if there is any string value passed in. | ||
| * @attr is-loading: boolean - Will display 'Loading...' when true. | ||
| * @attr all-options: string[] - This the list of all possible options | ||
| * the user can select from. | ||
| * @attr selected-options: string[] - If present in single-select, the selectedOption | ||
| * will be displayed as the value of the input. | ||
| * The list of options rendered will be all-options - selected-options | ||
| * @attr placeholder-text: string - This is the value to be displayed as a placeholder for the input. | ||
| * @property value: string[] - Will return the currently selected value(s). | ||
| * @event option__selection - This is emitted everytime a valid option is selected. | ||
| * detail { value: optionValue } | ||
| * **/ |
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.
I added this to help future dev know how to use this component.
|
This is so good i gotta get it merged asap. |
* Fix preview not updating when autosave is off - issue 120 (#125) * add soql-statement to model * verify that we include the soql statement in the model * update the package version so we can publish and consume * Add smarter completion on GROUP BY clause and WHERE literals (#126) * Initial support for Aggregate functions. Also: * Fix: Propose "COUNT()" only if right after "SELECT" * Remove special-case for "SELECT (SELECT ), | FROM Foo". Not worth it * Add completion inside function expression Example: SELECT AVG(|) FROM Also: * Improve ANTLR error recovery to better extract FROM expresssions * Make completions inside function expression type-aware * Add smarter completion on GROUP BY clause Also: * Complete only with "groupable" fields. * Give priority to complete GROUP BY with fields which appear on SELECT and are not aggregated or groupped. * On ORDER BY: Complete only with "sortable" fields * Add completion on semi-join SELECTs (in WHERE clauses) * Fix defect when cursor is around multiple newlines * Improve query analysis impl * Pre-select "WHERE" option if provided * Improve support for queries with semi-joins * Refactor: move soql operator semantics to LSP server-side * Add more code-completion proposals for literal values Including: * Range date literals (LAST_YEAR, YESTERDAY, LAST_N_DAYS:n, etc.) * Simple templates for: int, double, string, currency * Quiet completion on HAVING clause * Add a space before opening parenthesis after INCLUDES/EXCLUDES * New soql lsp version 0.3.3 (#140) * Feature/custom select (#148) * Jhork/custom select fields (#111) * Jhork/custom select from (#130) * Jhork/custom select order by (#134) * set the error overlay to be on top of all other form elements (#150) * set the error overlay to be on top of all other form elements * add z-index to .unsupported-syntax * prepare to publish 0 .0.30 (#151) Co-authored-by: Fernando Dobladez <fernandodobladez@salesforce.com> Co-authored-by: Jonny Hork <jhork@salesforce.com>
* Jhork: Support for Simple WHERE Expressions (#101) * move rule to css common (#108) * Preventing webview re-rendering when soql statement has not changed (#105) * Revert "Disable WHERE in model (#113)" * Type-aware where (#109) * Fix preview not updating when autosave is off - issue 120 (#125) * Recognize recoverable where errors (#116) * Operator and Criteria Error Tooltips (#122) * Support IN, NOT IN, INCLUDES, EXCLUDE operators (#123) * Add smarter completin on GROUP BY clause and WHERE literals (#126) * Feature/custom select (#148) * Jhork/custom select fields (#111) * Jhork/custom select from (#130) * Jhork/custom select order by (#134) * set the error overlay to be on top of all other form elements (#150) * prepare to publish 0 .0.30 (#151) * Feature/where (#154) * Jhork: Support for Simple WHERE Expressions (#101) * move rule to css common (#108) * Preventing webview re-rendering when soql statement has not changed (#105) * Revert "Disable WHERE in model (#113)" * Type-aware where (#109) * Recognize recoverable where errors (#116) * Operator and Criteria Error Tooltips (#122) * Support IN, NOT IN, INCLUDES, EXCLUDE operators (#123) * Revert "Feature/where (#154)" (#157) * Add support for line comments ( `//` ) at the top of SOQL files (#132) * Jhork/where custom select (#161) * Fix: 'undefined' in SOQL string (#162) * Clear tooltip when object changes, fix empty soql statement error blocker (#165) * Track to force render on condition change - fix rebase conflict (#166) * do not send event when user still adding input' (#169) * Jhork/clear modifier field bug fix (#168) * handle a option selection event (#178) * cler tooltip error when X is clicked (#180) * Jhork/workflow updates (#163) * Bump versions for release (#181) Co-authored-by: Jonny Hork <jhork@salesforce.com> Co-authored-by: dehru <599418+dehru@users.noreply.github.com> Co-authored-by: Dehru Cromer <dehru.cromer@salesforce.com> Co-authored-by: Fernando Dobladez <fernandodobladez@salesforce.com>
What does this PR do?
This PR will add support a single selection mode of the Custom Select component and other improvements. This PR will also replace the standard
<select>element with the Custom Select component to search and chose Objects in the SOQL builder.New Features
@api value : string[]can be used to query state of the component for selections made independently of the model. This will help with the WHERE clause when we need to know that a selection has been made but wait until all modifiers have a value before updating the model.⌃that will match standard<select>elements and toggle the options menu open or closed.Single Select Mode
Single.Select.Mode.mov
What issues does this PR fix or reference?
@W-8616118@