2020-10-06 09:01:51 +00:00
import React from "react" ;
import BaseWidget , { WidgetProps } from "./BaseWidget" ;
2022-05-25 09:46:14 +00:00
import { debounce , fromPairs } from "lodash" ;
2022-01-28 11:10:05 +00:00
import { EditorContext } from "components/editorComponents/EditorContextProvider" ;
2021-04-23 13:50:55 +00:00
import AppsmithConsole from "utils/AppsmithConsole" ;
import { ENTITY_TYPE } from "entities/AppsmithConsole" ;
2021-06-21 08:20:25 +00:00
import LOG_TYPE from "entities/AppsmithConsole/logtype" ;
2021-09-15 05:11:13 +00:00
import { ExecuteTriggerPayload } from "constants/AppsmithActionConstants/ActionConstants" ;
2022-05-25 09:46:14 +00:00
import { connect } from "react-redux" ;
import { getWidgetMetaProps } from "sagas/selectors" ;
2022-08-24 12:16:32 +00:00
import { AppState } from "@appsmith/reducers" ;
2020-10-06 16:47:16 +00:00
2022-04-08 06:09:23 +00:00
export type DebouncedExecuteActionPayload = Omit <
2021-09-15 05:11:13 +00:00
ExecuteTriggerPayload ,
2020-10-06 16:47:16 +00:00
"dynamicString"
2020-10-21 04:25:32 +00:00
> & {
dynamicString? : string ;
} ;
2020-10-06 09:01:51 +00:00
export interface WithMeta {
2020-10-06 16:47:16 +00:00
updateWidgetMetaProperty : (
propertyName : string ,
2022-02-25 20:46:04 +00:00
propertyValue : unknown ,
2020-10-06 16:47:16 +00:00
actionExecution? : DebouncedExecuteActionPayload ,
) = > void ;
2020-10-06 09:01:51 +00:00
}
2022-05-25 09:46:14 +00:00
type WidgetMetaProps = { metaState : Record < string , unknown > } ;
type metaHOCProps = WidgetProps & WidgetMetaProps ;
2022-02-25 20:46:04 +00:00
2022-05-25 09:46:14 +00:00
function withMeta ( WrappedWidget : typeof BaseWidget ) {
class MetaHOC extends React . PureComponent < metaHOCProps > {
2020-10-06 09:01:51 +00:00
static contextType = EditorContext ;
2022-05-25 09:46:14 +00:00
context ! : React . ContextType < typeof EditorContext > ;
2020-10-06 09:01:51 +00:00
2022-02-25 20:46:04 +00:00
initialMetaState : Record < string , unknown > ;
2022-05-25 09:46:14 +00:00
actionsToExecute : Record < string , DebouncedExecuteActionPayload > ;
updatedProperties : Record < string , boolean > ;
constructor ( props : metaHOCProps ) {
2020-10-06 09:01:51 +00:00
super ( props ) ;
const metaProperties = WrappedWidget . getMetaPropertiesMap ( ) ;
2022-02-25 20:46:04 +00:00
this . initialMetaState = fromPairs (
2020-12-24 04:32:25 +00:00
Object . keys ( metaProperties ) . map ( ( metaProperty ) = > {
2020-10-06 09:01:51 +00:00
return [ metaProperty , this . props [ metaProperty ] ] ;
} ) ,
) ;
2022-05-25 09:46:14 +00:00
this . updatedProperties = { } ;
this . actionsToExecute = { } ;
2020-10-06 09:01:51 +00:00
}
2022-05-25 09:46:14 +00:00
addPropertyForEval = (
propertyName : string ,
actionExecution? : DebouncedExecuteActionPayload ,
) = > {
// Add meta updates in updatedProperties to push to evaluation
this . updatedProperties [ propertyName ] = true ;
if ( actionExecution ) {
// Adding action inside actionsToExecute
this . actionsToExecute [ propertyName ] = actionExecution ;
2022-02-25 20:46:04 +00:00
}
2022-05-25 09:46:14 +00:00
} ;
2022-02-25 20:46:04 +00:00
2022-05-25 09:46:14 +00:00
removeBatchActions = ( propertyName : string ) = > {
delete this . actionsToExecute [ propertyName ] ;
} ;
runBatchActions = ( ) = > {
const { executeAction } = this . context ;
const batchActionsToRun = Object . entries ( this . actionsToExecute ) ;
batchActionsToRun . map ( ( [ propertyName , actionExecution ] ) = > {
if ( actionExecution && actionExecution . dynamicString && executeAction ) {
executeAction ( {
. . . actionExecution ,
dynamicString : actionExecution.dynamicString , // when we spread the object above check of dynamic string doesn't account for type.
source : {
id : this.props.widgetId ,
name : this.props.widgetName ,
} ,
} ) ;
// remove action from batch
this . removeBatchActions ( propertyName ) ;
actionExecution . triggerPropertyName &&
AppsmithConsole . info ( {
text : ` ${ actionExecution . triggerPropertyName } triggered ` ,
source : {
type : ENTITY_TYPE . WIDGET ,
id : this.props.widgetId ,
name : this.props.widgetName ,
} ,
} ) ;
2020-10-06 09:01:51 +00:00
}
} ) ;
2022-05-25 09:46:14 +00:00
} ;
handleTriggerEvalOnMetaUpdate = ( ) = > {
const { triggerEvalOnMetaUpdate } = this . context ;
// if we have meta property update which needs to be send to evaluation only then trigger evaluation.
// this will avoid triggering evaluation for the trailing end of debounce, when there are no meta updates.
if ( Object . keys ( this . updatedProperties ) . length ) {
if ( triggerEvalOnMetaUpdate ) triggerEvalOnMetaUpdate ( ) ;
this . updatedProperties = { } ; // once we trigger evaluation, we remove those property from updatedProperties
}
this . runBatchActions ( ) ;
} ;
debouncedTriggerEvalOnMetaUpdate = debounce (
this . handleTriggerEvalOnMetaUpdate ,
200 ,
{
leading : true ,
trailing : true ,
} ,
) ;
2020-10-06 09:01:51 +00:00
updateWidgetMetaProperty = (
propertyName : string ,
2022-02-25 20:46:04 +00:00
propertyValue : unknown ,
2020-10-06 16:47:16 +00:00
actionExecution? : DebouncedExecuteActionPayload ,
2020-10-06 09:01:51 +00:00
) : void = > {
2021-04-23 13:50:55 +00:00
AppsmithConsole . info ( {
2021-06-21 08:20:25 +00:00
logType : LOG_TYPE.WIDGET_UPDATE ,
2021-04-23 13:50:55 +00:00
text : "Widget property was updated" ,
source : {
type : ENTITY_TYPE . WIDGET ,
id : this.props.widgetId ,
name : this.props.widgetName ,
2021-06-21 08:20:25 +00:00
propertyPath : propertyName ,
2021-04-23 13:50:55 +00:00
} ,
state : {
[ propertyName ] : propertyValue ,
} ,
} ) ;
2022-05-25 09:46:14 +00:00
this . handleUpdateWidgetMetaProperty (
propertyName ,
propertyValue ,
actionExecution ,
2020-10-06 16:47:16 +00:00
) ;
2020-10-06 09:01:51 +00:00
} ;
2022-05-25 09:46:14 +00:00
handleUpdateWidgetMetaProperty = (
2021-03-01 14:56:47 +00:00
propertyName : string ,
2022-02-25 20:46:04 +00:00
propertyValue : unknown ,
2022-05-25 09:46:14 +00:00
actionExecution? : DebouncedExecuteActionPayload ,
) = > {
const { syncUpdateWidgetMetaProperty } = this . context ;
2023-02-14 16:07:31 +00:00
/ * *
* Some meta widget will have the actual widget 's widgetId as it' s widgetId .
* Eg - these are the widgets that are present in the first row of the List widget .
* For these widgets , it ' s expected for the meta updates to not go into the actual widgetId
* but a different internal id as over page changes the first row widgets should reflect distinct
* values entered in that particular page .
*
* Note : metaWidgetId would be undefined for all the non meta - widgets .
* /
const widgetId = this . props . metaWidgetId || this . props . widgetId ;
2021-03-01 14:56:47 +00:00
2022-05-25 09:46:14 +00:00
if ( syncUpdateWidgetMetaProperty ) {
syncUpdateWidgetMetaProperty ( widgetId , propertyName , propertyValue ) ;
// look at this.props.__metaOptions, check for metaPropPath value
// if they exist, then update the propertyName
// Below code of updating metaOptions can be removed once we have ListWidget v2 where we better manage meta values of ListWidget.
const metaOptions = this . props . __metaOptions ;
if ( metaOptions ) {
syncUpdateWidgetMetaProperty (
metaOptions . widgetId ,
` ${ metaOptions . metaPropPrefix } . ${ this . props . widgetName } . ${ propertyName } [ ${ metaOptions . index } ] ` ,
propertyValue ,
) ;
2020-10-06 16:47:16 +00:00
}
2022-05-25 09:46:14 +00:00
}
this . addPropertyForEval ( propertyName , actionExecution ) ;
this . setState ( { } , ( ) = > {
// react batches the setState call
// this will result in batching multiple updateWidgetMetaProperty calls.
this . debouncedTriggerEvalOnMetaUpdate ( ) ;
2020-10-06 09:01:51 +00:00
} ) ;
2022-05-25 09:46:14 +00:00
} ;
2020-10-06 09:01:51 +00:00
updatedProps = ( ) = > {
return {
2022-05-25 09:46:14 +00:00
. . . this . initialMetaState , // this contains stale default values and are used when widget is reset. Ideally, widget should reset to its default values instead of stale default values.
. . . this . props , // if default values are changed we expect to get new values from here.
. . . this . props . metaState ,
2020-10-06 09:01:51 +00:00
} ;
} ;
render() {
2022-05-25 09:46:14 +00:00
return (
< WrappedWidget
{ . . . this . updatedProps ( ) }
updateWidgetMetaProperty = { this . updateWidgetMetaProperty }
/ >
) ;
2020-10-06 09:01:51 +00:00
}
2022-05-25 09:46:14 +00:00
}
const mapStateToProps = ( state : AppState , ownProps : WidgetProps ) = > {
return {
2023-02-14 16:07:31 +00:00
metaState : getWidgetMetaProps ( state , ownProps ) ,
2022-05-25 09:46:14 +00:00
} ;
2020-10-06 09:01:51 +00:00
} ;
2022-05-25 09:46:14 +00:00
return connect ( mapStateToProps ) ( MetaHOC ) ;
}
2020-10-06 09:01:51 +00:00
export default withMeta ;