Closed adamstankiewicz closed 3 weeks ago
All modified and coverable lines are covered by tests :white_check_mark:
Project coverage is 83.89%. Comparing base (
ba3ff7e
) to head (5b53e4c
). Report is 1 commits behind head on master.
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
Closed in favor of https://github.com/openedx/frontend-plugin-framework/pull/84
Description
Context
Open edX instances (e.g., 2U) rely on third-party tools for logging and analytics (e.g., Datadog, Hotjar). Some of these tools end up ingesting PII into things such as session replays, etc. that should otherwise be masked.
Example vendor-specific approaches to masking UI elements from their ingested data:
data-dd-privacy="allow" | "mask" | "hidden" | "mask-user-input"
.data-hj-suppress
anddata-hj-allow
..fs-mask
,.fs-unmask
,.fs-exclude
, etc. class names.Currently, such attributes for Hotjar are hardcoded throughout the platform (search results), despite not all instances of Open edX using Hotjar. While these attributes are fairly benign, the current approach does not support extending the masking of PII to other vendors (e.g., Datadog).
Related, there are other vendor-specific HTML attributes and class names unrelated to PII this approach would also be applicable to. As such, the following implementation is generic to support "custom props" on annotated elements, regardless of whether it's for PII masking or otherwise.
Solution
Introduces a React hook (
useComponentPropOverrides
) and a Higher-Order-Component (withComponentPropOverrides
) as a mechanism to allow consumers to add one or more custom props (e.g., to mask PII within session replays) to any component that accepts prop spreading (e.g.,...props
).Configuration
May be configured by
env.config.js
or the MFE runtime configuration withcomponentPropOverrides
(open to other config property names):Usage
Consider the following JSX containing PII (i.e., username):
useComponentPropOverrides
(hook)withComponentPropOverrides
(HOC)By using
useComponentPropOverrides
(hook) orwithComponentPropOverrides
(HOC) to mask the username from third-party tools with the abovecomponentPropOverrides
configuration, the resulting HTML would render as the following:It does this by attempting to find a match between the component's specified selector and the
componentPropOverrides.targets.*
defined via configuration. If the specified selector matches one of the selectors defined via configuration, any configured props and their values be returned.Special cases
By default, components supporting configurable prop overrides only works with the prop
className
and any prop prefixed withdata-
(e.g.,data-dd-privacy
). Any other configuration prop name is ignored and not applied during rendering.In certain cases, components may opt-in to supporting overrides of explicitly named prop names (e.g.,
onClick
). By making the special cases like function handlers orstyle
opt-in within the MFE's base code, it provides opportunity to discuss/review which prop overrides are officially supported in any given component beyond the defaultdata-*
attributes orclassName
prop.className
Custom class name(s) will be concatenated with any existing
className
prop values that might already be passed to the component.style
Custom
style
properties will be shallow merged with any existingstyle
properties that might already exist for the component. If the style properties overlap, the customstyle
's value takes precedence.Functions (e.g.,
onClick
)If a custom prop is defined as a function (i.e., supported when
customComponentProps
is defined viaenv.config
) but the component itself already has anonClick
function handler, the component'sonClick
function will be executed first before calling the customonClick
handler. Both functions otherwise receive the same functionsargs
.Merge checklist:
frontend-platform
. This can be done by runningnpm start
and opening http://localhost:8080.module.config.js
file infrontend-build
.fix
,feat
) and is appropriate for your code change. Consider whether your code is a breaking change, and modify your commit accordingly.Post merge: