fp-ts: How to flatten one layer of an array of ReaderTaskEither? - fp-ts

I have the function getApps below
import * as RTE from 'fp-ts/es6/ReaderTaskEither';
type ContextResult<A> = RTE.ReaderTaskEither<LoggingContext, Error, A>;
const getApps: ContextResult<Apps[]>[] = marketplaceIds.map(
marketplaceId => getAppsFromUser(userId, marketplaceId),
);
I'm trying to flatten ContextResult<OwnedApp[]>[] to ContextResult<OwnedApp[]>. How to do it? I tried flat, flatMap and sequence but couldn't get it to work.

First, you need sequenceArray to turn ContextResult<Apps[]>[] into ContextResult<Apps[][]>.
When you. have F<T>[] and want to turn it into F<T[]>, sequenceArray is your friend.
Next, from ContextResult<Apps[][]> to ContextResult<Apps[]>, we can see that we change the type inside <> so we will use map here. The function passed in to map need to be in the shape of Apps[][] => Apps[], and that is Array.flatten
import * as RTE from 'fp-ts/es6/ReaderTaskEither';
import * as A from 'fp-ts/es6/ReadonlyArray';
import { pipe } from 'fp-ts/es6/function';
const flatted: ContextResult<readonly Apps[]> = pipe(
getApps,
RTE.sequenceArray,
RTE.map(A.flatten)
);

Related

How to get or filter a bunch of childNodes by their style class name in ReactJs

I am having trouble figuring out how to get or filter a bunch of childNodes by their style class name inside my useEffect. Using ReactJs v18.
Straight after the line with: const circleElements = launcherCircle!.childNodes; I would like to get/filter the div's with the class name 'launcherPos' so I can position them in a circle formation.
const LauncherComponent = () => {
const launcherCircleRef = useRef<HTMLDivElement>(null);
let modules: Module[] | null = GetModules();
const enableLauncher = (module: Module) => {
return !module.IsEnabled ? styles['not-active'] : null;
};
useEffect(() => {
const launcherCircle = launcherCircleRef.current;
const circleElements = launcherCircle!.childNodes;
let angle = 360 - 190;
let dangle = 360 / circleElements.length;
for (let i = 0; i < circleElements.length; i++) {
let circle = circleElements[i] as HTMLElement;
angle += dangle;
circle.style.transform = `rotate(${angle}deg) translate(${launcherCircle!.clientWidth / 2}px) rotate(-${angle}deg)`;
}
}, []);
if (modules == null){
return <Navigate replace to={'/noaccess'} />
} else {
return (
<div data-testid="Launcher" className={styles['launcherContainer']} >
<div className={styles['launcherCircle']} ref={launcherCircleRef}>
{modules.map(function (module: Module, idx) {
return (
<div key={idx} className={styles['launcherPos']} ><div className={`${styles['launcherButton']} ${enableLauncher(module)}`}><img src={module.ImagePath} alt={module.Prefix} /></div></div>
)
})}
<div className={styles['launcherTextDiv']}>
<span>TEST</span>
</div>
</div>
</div>
)
}
};
export default LauncherComponent;
From what I've read getElementsByClassName() is not advisable practise because of the nature of ReactJs and it's virtual DOM.
I tried the following filter but I think with React garburling the class name I didn't get anything back.
const launcherChildren = launcherCircle!.children;
const circleElements = [...launcherChildren].filter(element => element.classList.contains('launcherPos'));
Maybe there's a way to ref an array of the just the children with the launcherPos class???
There must be a couple of different ways, but, they are eluding me.
When you filter/map an array of HTMLElements, the results are in the form of objects, which contains properties like, props, ref etc.
Since className is a prop on the element, you should try looking for the class name by digging into the props key.
Simply put, all the props that you pass to the element, like onClick, onChange, value, className are stored under the props property.
You can filter the results by converting the class name into an array and further checking if it contains the target string (launcherPos in this case).
Your code should look something like this:
const circleElements = [...launcherChildren].filter(element=>element.props.className.split(' ').includes('launcherPos'))
The above method could be used when an array directly holds elements. E.g: [<div></div>,<div></div>...].
The approach that you've followed is correct, except for the way you are selecting the elements by their class names. I can see that you are using CSS modules in this component, meaning all the class names exist as properties on the imported object(styles in this case), so when you use contains('launcherPos') you are essentially checking for the presence of a string, but when using CSS modules, class names are available only as object properties, that's the reason you are getting an empty array. Simply update launcherPos to styles.launcherPos and that shall fix the issue.
All-in-all your useEffect function should look something like this:
useEffect(() => {
const launcherCircle = launcherCircleRef.current;
const launcherChildren = launcherCircle!.children;
const circleElements = [...launcherChildren].filter(element => element.classList.contains(styles.launcherPos)); //change launcherPos to styles.launcherPos
let angle = 360 - 190;
let dangle = 360 / circleElements.length;
for (let i = 0; i < circleElements.length; i++) {
let circle = circleElements[i] as HTMLElement;
angle += dangle;
circle.style.transform = `rotate(${angle}deg) translate(${launcherCircle!.clientWidth / 2}px) rotate(-${angle}deg)`;
}
}, []);

Tensorflow.js predict returning NaNs

I converted a keras model into a tensorflowjs model using the simple tensorflowjs_converter --input_format keras ./model/L_keypoint_classifier_final.h5 L_layer_model. I managed to get this model working on a .ts (TypeScript) file.
Now I am focused on deploying this model using React and Typescript (in a .tsx file). My app component is loading the models as such:
const [models, setModels] = useState<Models>({
L_Model: undefined,
R_Model: undefined,});
useEffect(() => {
loadModel().then((models) => {
setModels(models);
setIsLoading(false);
}); }
The loadModel() function is exported from another file and it is:
export async function loadModel() {
let result: Models = { R_Model: undefined, L_Model: undefined };
result.R_Model = await tf.loadLayersModel("/right/model.json");
result.L_Model = await tf.loadLayersModel("/left/model.json");
return result;
}
That directory of the models is in the public folder of my project. After loading the models in the app component, I pass them to a child component using props.
<Camera models={models}></Camera>
They are received in the camera component as:
const Camera: FunctionComponent<CameraProps> = (props) => {
const { R_Model, L_Model } = props.models;
In the camera component I pass in a tf.Tensor2D. This tensor does in fact contain values that I checked. But when I pass them to the model.predict() function, it just returns a tensor full of NaNs.
This is my code for preprocessing the input and passing it to the model:
//Preprocess Landmarks
//#ts-ignore
let landmark_list = calc_landmark_list(landmarks);
landmark_list = pre_process_landmarks(landmark_list);
//#ts-ignore
landmark_list = tf.tensor2d([landmark_list]);
console.log(landmarks_list.dataSync());
let prediction;
if(isRightHand){
prediction = R_Model?.predict(landmark_list);
}else{
prediction = L_Model?.predict(landmark_list);
}
const scores = prediction.arraySync()[0];
After that, I try to find the maxScore of the predictions, but since arraySync() returns a NaN array, it does not work. My team and me have try searchig for different options. Some include wrapping the predict function inside an aasync function, but that doesn't seem to work either (or maybe we have done it incorrectly, although we have followed the examples thoroughly).
The console.log of the landmark_list.dataSync() prints out:
Float32Array(42) [0, 0, -0.2683601677417755, -0.1023331806063652, -0.4781370162963867, -0.397993803024292, -0.5191399455070496, -0.6676312685012817, -0.46050554513931274, -0.8477477431297302, -0.30691489577293396, -0.9023468494415283, -0.49582260847091675, -1, -0.5734853148460388, -0.7551659941673279, -0.5509241223335266, -0.5708747506141663, -0.15572300553321838, -0.9109046459197998, -0.38624173402786255, -0.9391834735870361, -0.4641483426094055, -0.6930190920829773, -0.4609870910644531, -0.49743616580963135, -0.00984301045536995, -0.8530527353286743, -0.25299814343452454, -0.7750100493431091, -0.32405075430870056, -0.5182365775108337, -0.32825687527656555, -0.3154793083667755, 0.11740472167730331, -0.7356364130973816, -0.12479904294013977, -0.6477926969528198, -0.21985816955566406, -0.43255504965782166, -0.24492989480495453, -0.25398018956184387, buffer: ArrayBuffer(168), byteLength: 168, byteOffset: 0, length: 42, Symbol(Symbol.toStringTag): 'Float32Array']

Wordpress Gutenberg PluginDocumentSettingPanel not working with controls?

I want to add a custom meta field to the gutenberg document panel and used this doc. For the custom meta field I used this tutorial.
The problem I have occurs when trying to put them together.
Here is my code so far:
const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { InspectorControls } = wp.editor;
const { registerPlugin } = wp.plugins
const { PluginDocumentSettingPanel } = wp.editPost
const { PanelBody, PanelRow, TextControl } = wp.components
const PluginDocumentSettingPanelDemo = () => (
<PluginDocumentSettingPanel
name="custom-panel"
title="Custom Panel"
className="custom-panel"
>
<TextControl
value={wp.data.select('core/editor').getEditedPostAttribute('meta')['_myprefix_text_metafield']}
label={ "Text Meta" }
onChange={(value) => wp.data.dispatch('core/editor').editPost({meta: {_myprefix_text_metafield: value}})}
/>
</PluginDocumentSettingPanel>
)
registerPlugin('plugin-document-setting-panel-demo', {
render: PluginDocumentSettingPanelDemo
})
Edit: Thanks to Ivan I solved this side issue :)
My Sidebar looks okay at first:
But when I try to change the inputs value it isn't updated (but the storage in wp.data is). I can't delete it, too. It stays at it's initial value. When I remove the part where I set the initial value it works like it should be but since I need the initial value this isn't an option for me ;)
Here an example log from the console when I add an "x" to the end of the input (as mentioned above the text in the input itself doesn't change)
Does anyone know how to make the input field working properly?
First of all, make sure you have https://wordpress.org/plugins/gutenberg/ plugin installed, because PluginDocumentSettingPanel is not fully implemented in core WP yet. It should be for 5.3 version, as per these tweets.
Second, you don't need the interval function for the wp.plugins. The reason it is undefined at first is that WordPress doesn't know that you need the wp-plugins loaded first. From the WordPress documentation
If you wanted to use the PlainText component from the editor module, first you would specify wp-editor as a dependency when you enqueue your script
The same applies for all other modules (read scripts, like 'wp-plugins').
You have to add the 'wp-plugins' script as a dependency, when registering your js plugin script:
<?php
/*
Plugin Name: Sidebar plugin
*/
function sidebar_plugin_register() {
wp_register_script(
'plugin-sidebar-js',
plugins_url( 'plugin-sidebar.js', __FILE__ ),
array( 'wp-plugins', 'wp-edit-post', 'wp-element' ) // <== the dependencies array is important!
);
}
add_action( 'init', 'sidebar_plugin_register' );
function sidebar_plugin_script_enqueue() {
wp_enqueue_script( 'plugin-sidebar-js' );
}
add_action( 'enqueue_block_editor_assets', 'sidebar_plugin_script_enqueue' );
The PHP above is taken from the official WP documentation.
I would also suggest reading thoroughly this awesome tutorial from Css Tricks. It goes in depth about setting up an ESNext environment with only the #wordpress/scripts package. It goes over the dependencies, adding meta fields and much more :) I hope this helps!
--------------- Initial answer ends here ---------------
Edit: After testing the code from the author, I found out a couple of issues. First of all, there was a missing closing tag for the TextControl. Second, I added Higher order components from the wp-data package, which I then used to "enhance" the TextControl, so that it doesn't manipulate or read data directly, but abstract that logic into it's higher order components. The code looks like so:
const { __ } = wp.i18n;
const { registerPlugin } = wp.plugins;
const { PluginDocumentSettingPanel } = wp.editPost;
const { TextControl } = wp.components;
const { withSelect, withDispatch, dispatch, select } = wp.data;
// All the necessary code is pulled from the wp global variable,
// so you don't have to install anything
// import { withSelect, withDispatch, dispatch, select } from "#wordpress/data";
// !!! You should install all the packages locally,
// so your editor could access the files so you could
// look up the functions and classes directly.
// It will not add to the final bundle if you
// run it through wp-scripts. If not, you can
// still use the wp global variable, like you have done so far.
let TextController = props => (
<TextControl
value={props.text_metafield}
label={__("Text Meta", "textdomain")}
onChange={(value) => props.onMetaFieldChange(value)}
/>
);
TextController = withSelect(
(select) => {
return {
text_metafield: select('core/editor').getEditedPostAttribute('meta')['_myprefix_text_metafield']
}
}
)(TextController);
TextController = withDispatch(
(dispatch) => {
return {
onMetaFieldChange: (value) => {
dispatch('core/editor').editPost({ meta: { _myprefix_text_metafield: value } })
}
}
}
)(TextController);
const PluginDocumentSettingPanelDemo = () => {
// Check if a value has been set
// This is for editing a post, because you don't want to override it everytime
if (!select('core/editor').getEditedPostAttribute('meta')['_myprefix_text_metafield']) {
// Set initial value
dispatch('core/editor').editPost({ meta: { _myprefix_text_metafield: 'Your custom value' } });
}
return (
<PluginDocumentSettingPanel
name="custom-panel"
title="Custom Panel"
className="custom-panel"
>
<TextController />
</PluginDocumentSettingPanel>
)
};
registerPlugin('plugin-document-setting-panel-demo', {
render: PluginDocumentSettingPanelDemo
})
Since the meta field is registered with an underscore as a first symbol in the name, WordPress will not allow you to save it, because it treats it as a private value, so you need to add extra code, when registering the field:
function myprefix_register_meta()
{
register_post_meta('post', '_myprefix_text_metafield', array(
'show_in_rest' => true,
'type' => 'string',
'single' => true,
'sanitize_callback' => 'sanitize_text_field',
'auth_callback' => function () {
return current_user_can('edit_posts');
}
));
}
add_action('init', 'myprefix_register_meta');
Again, all of this is explained in the Css tricks tutorial.
I had the same problem - values were not being updated in the field and in the database - and, after some research, I have found that the reason for this is that you should add 'custom-fields' to the 'supports' array in your call to register_post_type(), like this:
register_post_type(
'my_post_type_slug',
array(
...
'supports' => array( 'title', 'editor', 'custom-fields' ),
...
)
);
You can test that this works by calling wp.data.select( 'core/editor' ).getCurrentPost().meta in your JavaScript console, when the block editor is loaded. If your post type does not add support for 'custom-fields', this call will return undefined; if it does, it will return an empty array (or rather, an array with the already existing meta from the database). This behavior is mentioned in the Gutenberg docs, in a note on registering your post meta:
To make sure the field has been loaded, query the block editor internal data structures, also known as stores. Open your browser’s console, and execute this piece of code:
wp.data.select( 'core/editor' ).getCurrentPost().meta;
Before adding the register_post_meta function to the plugin, this code returns a void array, because WordPress hasn’t been told to load any meta field yet. After registering the field, the same code will return an object containing the registered meta field you registered.
I worked on a similar implementation recently, and worked through a bunch of examples as well. Between the above-mentioned articles, and this great series by one of the Automattic devs, I got a working version of the above example using the newer useSelect and useDispatch custom hooks. It's really quite similar, but utilizes custom hooks from React 16.8 for a slightly more concise dev experience:
(Also, using #wordpress/scripts, so the imports are from the npm packages instead of the wp object directly, but either would work.)
import { __ } from '#wordpress/i18n';
import { useSelect, useDispatch } from '#wordpress/data';
import { PluginDocumentSettingPanel } from '#wordpress/edit-post';
import { TextControl } from '#wordpress/components';
const TextController = (props) => {
const meta = useSelect(
(select) =>
select('core/editor').getEditedPostAttribute('meta')['_myprefix_text_metafield']
);
const { editPost } = useDispatch('core/editor');
return (
<TextControl
label={__("Text Meta", "textdomain")}
value={meta}
onChange={(value) => editPost({ meta: { _myprefix_text_metafield: value } })}
/>
);
};
const PluginDocumentSettingPanelDemo = () => {
return (
<PluginDocumentSettingPanel
name="custom-panel"
title="Custom Panel"
className="custom-panel"
>
<TextController />
</PluginDocumentSettingPanel>
);
};
export default PluginDocumentSettingPanelDemo;
Hopefully that helps someone else searching.

Javascript and Typescript: iteration over object with for..of

From ES6 iteration over object values I took a way of iteration over object values. Here's my implementation:
function* entries (obj): IterableIterator<any> {
for (const key of Object.keys(obj)) {
const value = obj[key];
yield [
key,
value,
];
}
}
Then I want to use that in render() React Component's method:
render () {
const that = this;
const newVar = (() => {
const elements = [];
for (const [key, value] of entries(that.filters)) {
elements.push(<h2>{JSON.stringify(key)} {JSON.stringify(value)}</h2>);
}
return elements;
})();
return (
<section>
{newVar}
</section>
);
}
But if I debug this code with .map files in Chrome Developer console, newVar is an empty array. If I alert obj in entries generator I got proper object. Am I missing something really simple? Thank you in advance for every answer. I use Typescript with es5 option and I read that it supports generators: Generators and Iteration for ES5/ES3.
I use Typescript with es5 option and I read that it supports generators: Generators and Iteration for ES5/ES3.
It also says that you need to use the --downlevelIteration flag for that. Otherwise it will still transpile for … of-loops into array iteration, which fails on iterables like your generator instance without a .length property.

Displaying data from Firebase in React without arrays

I am new to both React and Firebase. I struggled a bit to get data from the database, even though the instructions on the Firebase website were pretty straightforward.
I managed to print data in the view by using this code:
Get data from DB and save it in state:
INSTRUMENTS_DB.once('value').then(function(snapshot) {
this.state.instruments.push(snapshot.val());
this.setState({
instruments: this.state.instruments
});
From Firebase, I receive and Object containing several objects, which correspond to the differen instruments, like shown in the following snippet:
Object {
Object {
name: "Electric guitar",
image: "img/guitar.svg"
}
Object {
name: "Bass guitar",
image: "img/bass.svg"
}
// and so on..
}
Currently, I print data by populating an array like this:
var rows = [];
for (var obj in this.state.instruments[0]) {
rows.push(<Instrument name={this.state.instruments[0][obj].name}
image={this.state.instruments[0][obj].image}/>);
}
I feel like there's a better way to do it, can somedody give a hint? Thanks
I user firebase a lot and mu solution is little ES6 helper function
const toArray = function (firebaseObj) {
return Object.keys(firebaseObj).map((key)=> {
return Object.assign(firebaseObj[key], {key});
})
};
I also assign the firebase key to object key property, so later I can work with the keys.
The native map function only works for arrays, so using directly it on this object won't work.
What you can do instead is:
Call the map function on the keys of your object using Object.keys():
getInstrumentRows() {
const instruments = this.state.instruments;
Object.keys(instruments).map((key, index) => {
let instrument = instruments[key];
// You can now use instrument.name and instrument.image
return <Instrument name={instrument.name} image={instrument.image}/>
});
}
Alternatively, you can also import the lodash library and use its map method which would allow you to refactor the above code into:
getInstrumentRowsUsingLodash() {
const instruments = this.state.instruments;
_.map(instruments, (key, index) => {
let instrument = instruments[key];
// You can now use instrument.name and instrument.image
return <Instrument name={instrument.name} image={instrument.image}/>
});
}
Side note:
When you retrieve you data from Firebase you attempt to update the state directly with a call on this.state.instruments. The state in React should be treated as Immutable and should not be mutated with direct calls to it like push.
I would use map function:
_getInstrumentRows() {
const instruments = this.state.instruments[0];
if (instruments) {
return instruments.map((instrument) =>
<Instrument name={instrument.name}
image={instrument.image}/>);
}
}
In your render() method you just use {_getInstrumentRows()} wherever you need it.

Resources