-
Notifications
You must be signed in to change notification settings - Fork 87
Cluster Feature Page - Enable feature toggling and sync with device type feature page #1604
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
base: master
Are you sure you want to change the base?
Conversation
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.
Hello @ethanzhouyc, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
Summary of Changes
Hello team, gemini-code-assist here with a summary of this pull request. The primary goal of this PR is to enable users to toggle features directly within the Cluster Feature page. To achieve this, the changes include significant work to synchronize the feature state and the featureMap
attribute value between the Device Type and Cluster Feature pages. A substantial portion of shared logic related to feature management and conformance checking has been extracted into a new Vue mixin for better code reuse. Additionally, the warning system has been improved to more accurately display warnings, disable feature toggles when necessary due to conformance issues, and remove outdated warnings, with refined warning messages for clarity. Backend database queries and REST endpoints supporting these frontend changes have also been updated or added, along with corresponding unit tests.
Highlights
- Feature Toggling on Cluster Page: Enables the ability for users to toggle features directly from the Cluster Feature view, which was previously only possible on the Device Type Feature page.
- Sync Feature State Across Pages: Implements logic to ensure that the state of features (enabled/disabled) and the value of the
featureMap
attribute are synchronized and correctly reflected on both the Device Type and Cluster Feature pages. - Shared Feature Logic Mixin: Extracts common frontend logic for managing features, handling toggles, displaying confirmation dialogs, and interacting with the backend conformance checks into a new
feature-mixin.js
file, promoting code reuse across relevant Vue components. - Enhanced Conformance Warning System: Improves the system for checking element and feature conformance when a feature is toggled. This includes displaying specific warnings, disabling toggles if a change would lead to incorrect conformance that cannot be automatically resolved, and automatically clearing outdated warnings.
- Backend Query and REST API Updates: Refactors several backend database queries to simplify parameters (removing
deviceTypeClusterId
) and adds a new query to find the server-side endpoint type cluster ID. Updates REST endpoints for checking conformance and retrieving feature map data, changing some from GET to POST and adjusting the data returned. - Refined Conformance Evaluation: Updates the conformance evaluation logic to better handle complex expressions, including terms with numbers and the
desc
term, and adds functions to identify dependent features whose conformance might change.
Changelog
Click here to see the changelog
- src-electron/db/db-mapping.js
- Renamed
id
tofeatureId
andclusterId
toclusterRef
in theclusterFeature
mapping (L283, L290). - Added
id
mapping forENDPOINT_TYPE_ATTRIBUTE_ID
inendpointTypeAttributeExtended
(L661).
- Renamed
- src-electron/db/query-attribute.js
- Renamed
selectAttributesByEndpointTypeClusterIdAndDeviceTypeClusterId
toselectAttributesByEndpointTypeClusterId
(L1278). - Removed
deviceTypeClusterId
parameter and related join condition fromselectAttributesByEndpointTypeClusterId
query (L1279, L1312). - Updated export name for the renamed function (L1341).
- Renamed
- src-electron/db/query-command.js
- Renamed
selectCommandsByEndpointTypeClusterIdAndDeviceTypeClusterId
toselectCommandsByEndpointTypeClusterId
(L2064). - Removed
deviceTypeClusterId
parameter and related join condition fromselectCommandsByEndpointTypeClusterId
query (L2065, L2095). - Updated export name for the renamed function (L2150).
- Renamed
- src-electron/db/query-endpoint-type.js
- Renamed
getEndpointTypeElements
and removeddeviceTypeClusterId
parameter (L782). - Updated calls to attribute, command, and event queries to remove the
deviceTypeClusterId
parameter (L786, L790, L792).
- Renamed
- src-electron/db/query-event.js
- Renamed
selectEventsByEndpointTypeClusterIdAndDeviceTypeClusterId
toselectEventsByEndpointTypeClusterId
(L244). - Removed
deviceTypeClusterId
parameter and related join condition fromselectEventsByEndpointTypeClusterId
query (L245, L275). - Updated export name for the renamed function (L279).
- Renamed
- src-electron/db/query-session-notification.js
- Updated
setNotificationOnFeatureChange
to accept and processoutdatedWarningPatterns
for deleting old notifications (L212, L219).
- Updated
- src-electron/db/query-zcl.js
- Added new query
selectServerEndpointTypeClusterIdByEndpointTypeIdAndClusterRef
to find the server-side endpoint type cluster ID (L1121-L1153). - Added
ETA.ENDPOINT_TYPE_ATTRIBUTE_ID
to the select list inselectEndpointTypeAttributesByEndpointId
query (L1213). - Exported the new query function (L1345).
- Added new query
- src-electron/rest/user-data.js
- Renamed
httpGetRequiredElements
tohttpPostRequiredElements
and changed it to a POST request (L172). - Renamed
httpGetFeatureMapValue
tohttpGetFeatureMapAttribute
and updated it to return the full attribute object instead of just the value (L202, L212). - Updated
httpPostCheckConformOnFeatureUpdate
to usegetEndpointTypeClusterIdFromFeatureData
and passclusterFeatures
(L122, L138). - Updated
httpPostRequiredElementWarning
to pass the entire request body to the query function (L149). - Updated endpoint registrations to reflect the changes (L1273, L1336).
- Renamed
- src-electron/validation/conformance-checker.js
- Removed
filterRelatedDescElements
function (L26-L47). - Updated
generateWarningMessage
to include checks fordesc
and dependent features, refine warning messages, and generateoutdatedWarningPatterns
(L89-L113, L162-L214). - Updated
checkElementConformance
to usefilterRelatedDescElements
andcheckFeaturesToUpdate
fromconformance-expression-evaluator.js
and passclusterFeatures
(L273, L277, L281, L292). - Updated
getOutdatedElementWarning
to acceptfeatureCode
directly instead offeatureData
(L369). - Updated
filterRequiredElements
to use the newgetConformanceTermStates
function (L427). - Added
getEndpointTypeClusterIdFromFeatureData
function (L626-L651). - Added
getConformanceTermStates
function (L460-L494). - Exported new functions and removed export for the moved function (L653-L658).
- Removed
- src-electron/validation/conformance-expression-evaluator.js
- Added
TERM_REGEX
constant (L26). - Updated
evaluateConformanceExpression
andcheckMissingTerms
to use the newgetTermsFromExpression
function (L48, L77, L127). - Added
checkIfExpressionHasTerm
function (L145-L147). - Added
getTermsFromExpression
function (L156-L160). - Added
filterRelatedDescElements
function (L162-L178). - Added
checkFeaturesToUpdate
function (L181-L242). - Exported new functions (L244-L249).
- Added
- src-electron/validation/conformance-xml-parser.js
- Added handling for
describedConform
to return thedesc
conformance term (L150-L151).
- Added handling for
- src-shared/rest-api.js
- Renamed
featureMapValue
URI tofeatureMapAttribute
(L40).
- Renamed
- src/components/ZclAttributeManager.vue
- Added
featureMixin
to mixins (L248).
- Added
- src/components/ZclClusterFeatureManager.vue
- Updated template to use
clusterFeatures
instead offeatureData
(L19, L22). - Updated template to use
enabledClusterFeatures
andfeatureId
instead ofenabledFeatures
andid
for the toggle value (L44, L45). - Added
@update:model-value
handler to callonToggleFeature
(L48). - Added confirmation dialog template (L69-L145).
- Added
featureMixin
to mixins (L160). - Removed local computed properties
featureData
,featureMapValue
,enabledFeatures
(now in mixin). - Updated
isToggleDisabled
logic to disable based on 'disallowed' or 'deprecated' conformance (L165-L168). - Removed local
getEnabledBitsFromFeatureMapValue
method (now in mixin).
- Updated template to use
- src/components/ZclClusterView.vue
- Added binary representation display for the FeatureMap attribute value in the template (L120-L124).
- Added
featureMixin
to mixins (L170).
- src/components/ZclDeviceTypeFeatureManager.vue
- Updated template to use
featureId
directly for the toggle value instead of the hashed value (L73). - Updated
@update:model-value
handler to call the genericonToggleFeature
from the mixin (L76). - Removed local methods
onToggleDeviceTypeFeature
,confirmFeatureUpdate
,setFeatureMapAttribute
,processElementsForDialog
,displayPopUpWarnings
,buildFeatureMap
,featureIsEnabled
(moved tofeature-mixin.js
). - Removed local computed property
noElementsToUpdate
(moved to mixin). - Removed local data properties related to the confirmation dialog (
showDialog
,attributesToUpdate
, etc.) (moved to mixin).
- Updated template to use
- src/components/ZclDomainClusterView.vue
- Added
featureMixin
to mixins (L248). - Changed call from
setFeatureMapAttribute
toloadFeatureMapAttribute
and updated logic to use the mixin function (L701).
- Added
- src/store/zap/actions.js
- Renamed
updateFeatureMapValue
toupdateFeatureMapAttribute
and updated it to fetch the full attribute object and parse the default value into thevalue
property (L140-L149). - Updated
setDeviceTypeFeatures
to pushfeature.featureId
directly toenabledDeviceTypeFeatures
instead of the Cantor pair hash (L1010). - Changed
setRequiredElements
to use$serverPost
instead of$serverGet
with params (L1039).
- Renamed
- src/store/zap/mutations.js
- Renamed
updateFeatureMapValue
toupdateFeatureMapAttribute
and updated it to store the full attribute object (L201). - Renamed
updateFeatureMapAttributeOfFeature
toupdateFeatureMapAttributeOfDeviceTypeFeatures
(L1181). - Updated comment for
updateConformDataExists
mutation (L1193).
- Renamed
- src/store/zap/state.js
- Changed
featureMapValue
(number) tofeatureMapAttribute
(object) in the state definition (L52).
- Changed
- src/util/common-mixin.js
- Removed computed properties
deviceTypeFeatures
,deviceTypeFeatureInSelectedCluster
,featureMap
,featureMapValue
,enabledDeviceTypeFeatures
(moved tofeature-mixin.js
) (L125-L162). - Removed methods
setRequiredConformElement
andhashDeviceTypeClusterIdFeatureId
(moved/updated infeature-mixin.js
) (L420-L438).
- Removed computed properties
- src/util/feature-mixin.js
- Added new file containing shared logic for feature management across different views.
- test/feature.test.js
- Added
clusters
andonOffCluster
variables inbeforeAll
for reuse (L46, L47, L108, L109). - Updated test description for conformance evaluation to include term extraction (L160).
- Updated conformance expression test cases to include expected
terms
array (L172-L340). - Added assertion to check extracted terms using
conformEvaluator.getTermsFromExpression
(L349, L350). - Updated calls to
filterRelatedDescElements
to useconformEvaluator
(L369, L379). - Updated calls to
checkElementConformance
to passclusterFeatures
(L478, L504, L532, L561, L587). - Updated expected warning messages for clarity and to match the new format (L509, L536, L566).
- Updated the API test for feature map to use the new
featureMapAttribute
endpoint and expect the full attribute object (L616). - Added test for
getEndpointTypeClusterIdFromFeatureData
(L632-L665). - Added test for
getConformanceTermStates
(L668-L692). - Added test for
checkFeaturesToUpdate
(L694-L741).
- Added
- test/importexport.test.js
- Updated expected warning messages to match the new format (L517, L522, L527, L534).
- test/multi-protocol.test.js
- Added
console.log
for debugging (L185). - Updated expected warning messages to match the new format (L190, L196, L203, L228).
- Added
- test/notification.test.js
- Added a test case to verify the deletion of outdated notifications using patterns (L417-L435).
- test/query.test.js
- Updated calls to
selectAttributesByEndpointTypeClusterIdAndDeviceTypeClusterId
andselectCommandsByEndpointTypeClusterIdAndDeviceTypeClusterId
to use the new names and remove thedeviceTypeClusterId
parameter (L648, L659). - Added a test for
selectServerEndpointTypeClusterIdByEndpointTypeIdAndClusterRef
(L674-L695).
- Updated calls to
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command>
or @gemini-code-assist <command>
. Below is a summary of the supported commands.
Feature | Command | Description |
---|---|---|
Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/
folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Features now toggle free,
Across pages, in harmony.
Warnings guide the way,
Code reused today,
In mixins, logic you'll see.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
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.
Code Review
This pull request introduces significant enhancements to feature management, including enabling feature toggling in the cluster feature page, syncing feature states with the device type feature page, and a substantially improved warning system. The refactoring of shared logic into feature-mixin.js
is a great step for code organization and reusability. The database query simplifications and the more robust conformance checking logic are also noteworthy improvements. The added unit tests are crucial for such a complex feature.
Overall, the changes are well-structured and address the described objectives. The new warning system, in particular, seems much more comprehensive.
Summary of Findings
- Refactoring and Code Organization: The introduction of
feature-mixin.js
centralizes feature toggling logic, significantly improving code organization and reusability across components. This is a very positive change. - Database Query Simplification: Database queries for attributes, commands, and events have been simplified by consistently using
endpointTypeClusterId
and removing reliance ondeviceTypeClusterId
where appropriate. This makes the data retrieval logic more direct. - Enhanced Warning System: The warning system has been substantially improved. It now generates more specific and context-aware warnings, handles inter-dependent feature conformance, and includes a mechanism for deleting outdated warnings. This will greatly improve the user experience.
- Conformance Checking Logic: The conformance checking logic in
conformance-checker.js
andconformance-expression-evaluator.js
has been expanded, notably with thecheckFeaturesToUpdate
function, to better handle complex scenarios and dependencies between features. - API Endpoint Changes: REST API endpoints for
requiredElements
(now POST) andfeatureMapAttribute
(response change) have been updated. Frontend adaptations seem to be in place. - Vuex State Management: Vuex state, actions, and mutations related to feature maps and enabled features have been updated consistently with the new approach (e.g., using
featureId
directly).
Merge Readiness
This pull request introduces substantial and valuable improvements to feature management. The refactoring and new logic are complex but appear well-implemented, and the enhanced warning system is a significant step forward. The inclusion of new unit tests is commendable.
I have a few medium
severity comments, mostly seeking clarification or pointing to areas of complexity that warrant careful consideration. Addressing these would further strengthen the PR.
As an AI, I am not authorized to approve pull requests. Please ensure thorough testing and review by other team members before merging. Given the scope of changes, a final round of integration testing focusing on the feature toggling and warning system across different scenarios would be beneficial.
Object.keys(featuresToUpdate).length == 0 | ||
) { |
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 condition Object.keys(featuresToUpdate).length == 0
has been added to determine if a feature change should be enabled. This is a good check to prevent changes if they would require other features to be updated first. Could you confirm if there are scenarios where featuresToUpdate
might be populated but the change should still be allowed, perhaps with a different type of warning, or is disabling the change always the correct action in this case?
/** | ||
* Check which features need to be updated or have conformance changes due to the updated feature. | ||
* | ||
* @param {*} updatedFeatureCode | ||
* @param {*} clusterFeatures | ||
* @param {*} elementMap | ||
* @returns {Object} Contains: | ||
* - updatedFeatures: Map of features with incorrect conformance that need to be updated. | ||
* - changedConformFeatures: Array of feature objects with conformance value changed after the feature update. | ||
*/ | ||
function checkFeaturesToUpdate( | ||
updatedFeatureCode, | ||
clusterFeatures, | ||
elementMap | ||
) { | ||
// build a map of feature codes to their conformance expressions | ||
let featureConformance = clusterFeatures.reduce((map, feature) => { | ||
map[feature.code] = feature.conformance | ||
return map | ||
}, {}) | ||
|
||
let updatedFeatures = {} | ||
let changedConformFeatures = [] | ||
for (let [featureCode, expression] of Object.entries(featureConformance)) { | ||
if (featureCode == updatedFeatureCode) { | ||
continue | ||
} | ||
|
||
// skip if conformance is not related to the updated feature | ||
let terms = getTermsFromExpression(expression) | ||
if (!terms.includes(updatedFeatureCode)) { | ||
continue | ||
} | ||
|
||
let conformance = evaluateConformanceExpression(expression, elementMap) | ||
|
||
if (conformance == 'mandatory' && !elementMap[featureCode]) { | ||
updatedFeatures[featureCode] = true | ||
} | ||
if (conformance == 'notSupported' && elementMap[featureCode]) { | ||
updatedFeatures[featureCode] = false | ||
} | ||
|
||
let oldElementMap = { ...elementMap } | ||
oldElementMap[updatedFeatureCode] = !oldElementMap[updatedFeatureCode] | ||
let oldConformance = evaluateConformanceExpression( | ||
expression, | ||
oldElementMap | ||
) | ||
|
||
// compare conformance before and after the feature update | ||
if (conformance !== oldConformance) { | ||
changedConformFeatures.push(featureCode) | ||
} | ||
} | ||
|
||
changedConformFeatures = changedConformFeatures.map((code) => { | ||
return clusterFeatures.find((feature) => feature.code == code) | ||
}) | ||
|
||
return { updatedFeatures, changedConformFeatures } | ||
} |
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 new checkFeaturesToUpdate
function introduces logic to identify features whose conformance state or value might change due to a feature toggle. This is a key part of the improved warning system.
Given its complexity and importance:
- Are there specific edge cases around complex conformance expressions (e.g., nested conditions, multiple dependencies) that were particularly challenging to test for this function?
- The function identifies
updatedFeatures
(features that must change state) andchangedConformFeatures
(features whose conformance value changes). Is the distinction clear and consistently used in the warning generation logic inconformance-checker.js
? It appears to be, withupdatedFeatures
leading to disabling the primary change andchangedConformFeatures
contributing tooutdatedWarningPatterns
.
if (this.featureMapValue) { | ||
feature.featureMapValue = this.featureMapValue | ||
feature.featureMapAttributeId = this.featureMapAttribute.id | ||
} |
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.
In the clusterFeatures
computed property, feature.featureMapValue
and feature.featureMapAttributeId
are assigned only if this.featureMapValue
is truthy. If this.featureMapValue
is 0
(a valid state meaning no features are enabled via the map), these properties on the feature
object won't be set. Is this the intended behavior? It seems featureMapValue
would still be relevant as 0
for determining enabled bits, and featureMapAttributeId
might still be needed if the user intends to enable a feature on a map that's currently 0
.
// build new feature map after both device type and cluster feature updates | ||
buildFeatureMap(inclusionList, updatedFeature = null) { | ||
let featureMap = {} | ||
if (updatedFeature) { | ||
// for device type feature updates, merge cluster feature data into inclusionList | ||
let clusterInclusionList = [...this.enabledClusterFeatures] | ||
// handle edge case for disabling a device type feature: remove it from cluster inclusionList | ||
if (!this.featureIsEnabled(updatedFeature, inclusionList)) { | ||
clusterInclusionList = clusterInclusionList.filter( | ||
(featureId) => featureId !== updatedFeature.featureId | ||
) | ||
} | ||
inclusionList = [...clusterInclusionList, ...inclusionList] | ||
} | ||
this.clusterFeatures.forEach((feature) => { | ||
featureMap[feature.code] = this.featureIsEnabled(feature, inclusionList) | ||
}) | ||
return featureMap |
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 logic in buildFeatureMap
for merging enabledClusterFeatures
with inclusionList
when updatedFeature
is present (i.e., a toggle from the device type page) is crucial for consistency. The handling of disabling a device type feature by filtering it out of clusterInclusionList
seems correct. This ensures the featureMap
accurately reflects the intended combined state. This is a well-thought-out detail.
Great job @ethanzhouyc |
|
Issue created for writing documentation covering cluster feature page, feature compliance warnings, and introduction on conformance. |
Planning to display a natural language translation for all conformance expressions, and add an info icon guiding users to the documents explaining the conformance and warnings. |
New Feature: Enable users to toggle features in the cluster feature page
Sync between device type and cluster feature page:
feature-mixin.js
for code reuseImprove warning system:
Testing:
The PR is large, but all changes are necessary to deliver a functional and bug-free feature page.