Redux Store Structure¶
The taranta front end has single redux store. This redux store is used to store data for devices & dashboard tab. This store can also be used to store data for future additions in taranta. Hence when user lands initially on devices or dashboard tab, entire store object is loaded which is mostly empty. This store object is populated as user navigates.
For example if user is on testdb/devices route all devices from testdb database along with database info is fetched and stored on store.
deviceList: {
nameList: [
'dserver/databaseds/2',
'dserver/starter/45ba3714711d',
'dserver/tangoaccesscontrol/1',
'dserver/tangotest/test',
'dserver/tarantatestdevice/test',
'dserver/tarantatestdevice/test2',
'sys/access_control/1',
'sys/database/2',
'sys/tg_test/1',
'tango/admin/45ba3714711d',
'test/tarantatestdevice/1',
'test/tarantatestdevice/2'
]
},
database: {
info: 'TANGO Database sys/database/2\n \nRunning since 2023-05-04 07:59:44\n \nDevices defined = 12\nDevices exported = 10\nDevice servers defined = 6\nDevice servers exported = 5\n \nDevice properties defined = 217 [History lgth = 217]\nClass properties defined = 84 [History lgth = 180]\nDevice attribute properties defined = 0 [History lgth = 0]\nClass attribute properties defined = 0 [History lgth = 0]\nObject properties defined = 0 [History lgth = 0]\n',
tangoDBName: 'testdb'
},
When user clicks on specific device then device details are loaded on the store and the same is used to render the page.
When user navigates from devices to dashboard tab then dashboard relevant details are loaded in the store. Populating redux store with data as user navigates on the UI helps to keep store object light. The light store object approach helps to reduce un-necessary page rendering upto some extent because with every change in store subscribed components are rendered again Also note while navigating between devices & dashboard tab store data is not lost.
Adding data in store¶
Now that we have common store for dashboard & devices tab hence any store related code will go under src/shared/state folder. Redux entities will be stored as below:
Redux ActionsTypes & Actions will go under src/shared/state/actions folder
Redux reducers will go under src/shared/state/reducers folder
Redux selectors will go under src/shared/state/selectors folder
Saga will go under src/shared/state/sagas folder
Once above code is in place, then we just need to trigger the respective redux action, this will load the store with data & same store data is used to render the page. For some redux action we may need to fetch data from dashboard-repo or auth repo, in such case saga is used to fetch data asynchronously and then this data is added in store with help of reducers.
For example when taranta Devices tab is open a couple of actions are triggered:
1. FETCH_DEVICES_NAME
action that results in FETCH_DEVICE_NAMES_SUCCESS
or FETCH_DEVICE_NAMES_FAILED
in case of success the following structure is added to the redux state:
deviceList: {
nameList: [
"dserver/databaseds/2",
"dserver/starter/17a39f945d53",
"dserver/tangoaccesscontrol/1",
"dserver/tangotest/test",
"dserver/tarantatestdevice/test",
"sys/access_control/1",
"sys/database/2",
"sys/tg_test/1",
"tango/admin/17a39f945d53",
"test/tarantatestdevice/1"
]
}
This information is then used to populate DeviceList component:
2. FETCH_DATABASE_INFO
action that results in FETCH_DATABASE_INFO_SUCCESS
or FETCH_DATABASE_INFO_FAILED
in case of success the following structure is added to the redux state:
database: {
info: 'TANGO Database sys/database/2
Running since 2023-01-16 14:28:23
Devices defined = 10
Devices exported = 10
Device servers defined = 5
Device servers exported = 5
Device properties defined = 215 [History lgth = 215]
Class properties defined = 84 [History lgth = 36]
Device attribute properties defined = 0 [History lgth = 0]
Class attribute properties defined = 0 [History lgth = 0]
Object properties defined = 0 [History lgth = 0]'
}
This information is then used to populate InfoPage component:
When a user clicks in a device, example:
FETCH_DEVICE
action is trigger, that results in FETCH_DEVICE_SUCCESS
or FETCH_DEVICE_FAILED
in case of success the following structure is added to the redux state:
devices: {
"sys/access_control/1": {
"connected": true,
"state": "ON",
"server": {
"id": "TangoAccessControl/1",
"host": "17a39f945d53"
},
"errors": [],
"name": "sys/access_control/1"
}
},
attributes: {
"sys/access_control/1": {
"state": {
"name": "state",
"label": "State",
"dataformat": "SCALAR",
"datatype": "DevState",
"writable": "READ",
"description": "No description",
"displevel": "OPERATOR",
"minvalue": null,
"maxvalue": null
},
"status": {
"name": "status",
"label": "Status",
"dataformat": "SCALAR",
"datatype": "DevString",
"writable": "READ",
"description": "No description",
"displevel": "OPERATOR",
"minvalue": null,
"maxvalue": null
}
}
},
commands: {
"sys/access_control/1": {
"AddAddressForUser": {
"name": "AddAddressForUser",
"tag": 0,
"displevel": "OPERATOR",
"intype": "DevVarStringArray",
"intypedesc": "user name, address",
"outtype": "DevVoid",
"outtypedesc": "Uninitialised"
},
...
"State": {
"name": "State",
"tag": 0,
"displevel": "OPERATOR",
"intype": "DevVoid",
"intypedesc": "Uninitialised",
"outtype": "DevState",
"outtypedesc": "Device state"
},
"Status": {
"name": "Status",
"tag": 0,
"displevel": "OPERATOR",
"intype": "DevVoid",
"intypedesc": "Uninitialised",
"outtype": "DevString",
"outtypedesc": "Device status"
},
}
},
properties: {
"sys/access_control/1": {}
}
This information is then used to populate all the following devices tabs: