Sonarqube : Create a custom page using react - reactjs

I would like to create a custom page using react but I cannot find the documentation to do this. On the Sonarqube documentation, there only the way to create a custom page using javascript only and I don’t understand how the example plugin works with react.
Can you tell me if there is a documentation that I can use.

Short answer: There isn't. There is barely anyone (no one in fact, as far as I've seen) using custom pages currently.
However, it IS possible. You need to create a react project with Webpack (or a similar JS packager).
I also recommend using Create-React-App. This fixes a lot of the setup for you. After that, in your index.js you use the example code from the SonarQube wiki.
Here is an example:
/*
PRODUCTION ENTRYPOINT
*/
import React from 'react';
import ReactDOM from 'react-dom';
import Project from './components/Project';
import './main.css';
window.registerExtension('myplugin/coverage', function (options) {
appendCustomCSS();
let isDisplayed = true;
window.SonarRequest.getJSON('/api/measures/component', {
component: options.component.key,
metricKeys: 'coverage'
}).then(function (response) {
if (isDisplayed) {
let obj = JSON.parse(response.component.measures[0].value);
let div = document.createElement('div');
render(obj, div);
options.el.appendChild(div);
}
});
return function () {
isDisplayed = false;
};
});
function appendCustomCSS() {
let fileref = document.createElement("link");
fileref.setAttribute("rel", "stylesheet");
fileref.setAttribute("type", "text/css");
fileref.setAttribute("href", "/static/myplugin/coverage.css");
document.head.append(fileref);
}
function render(objectArray, container) {
ReactDOM.render(<div className="Coverage"><Project objects={objectArray}/></div>, container);
}

Related

Error: Zxing functions does not exists. React QR Scanning App

I am trying add a qr code scanning functionality to my react app. I am using #zxing(https://www.npmjs.com/package/#zxing/browser & https://www.npmjs.com/package/#zxing/library) packages.
Following the readme, here's my js code. I have hosted the application on aws so its SSL covered. But I can't seem to figure out the issue. I have read the git repo of both and the functions do exists(https://github.com/zxing-js/browser/tree/master/src/readers)
import React, { useState, useEffect } from "react";
import {
NotFoundException,
ChecksumException,
FormatException
} from "#zxing/library";
import { BrowserQRCodeReader, BrowserCodeReader } from '#zxing/browser';
export default function() {
var qrCodeReader = null;
var codeReader = null;
var sourceSelect = null;
console.log("ZXing code reader initialized");
useEffect(() => {
codeReader = new BrowserCodeReader();
qrCodeReader = new BrowserQRCodeReader();
console.log(codeReader.listVideoInputDevices()); // ISSUE: RETURNS -> listVideoInputDevices() is not a fuction
console.log(qrCodeReader.listVideoInputDevices()); // ISSUE: RETURNS -> listVideoInputDevices() is not a fuction
console.log("Code Reader", codeReader); // ISSUE: SEE IMAGE BELOW
console.log("QR Code Reader", qrCodeReader); // ISSUE: SEE IMAGE BELOW
}, []);
Instead of using the import try using:
`
const zxing = require('zxing-js/library');
`

How can I selectively render code in a Create React App SPA?

In my React app (built with Create React App cli, and not ejected) I have it set up so if there is no REACT_APP_API_URL defined then it uses mocked data.
I do this by suppling a fakeFetch function to redux-api-middleware ala
import { apiMiddleware as aMl, createMiddleware } from 'redux-api-middleware'
import fakeFetch from 'fixtures/utils/fakeFetch'
const apiMiddleware = apiBase ? aMl : createMiddleware({ fetch: fakeFetch })
// etc... configure the `redux` store with the middleware
That's fine when developing, but I'd like for that code to be completely detached from the build when actually building for deployment.
Is there any way I can do something along the lines of
<% if process.env.REACT_APP_API_URL %>
import { apiMiddleware } from 'redux-api-middleware'
<% else %>
import { createMiddleware } from 'redux-api-middleware'
import fakeFetch from 'fixtures/utils/fakeFetch'
const apiMiddleware = createMiddleware({ fetch: fakeFetch })
<% endif %>
// etc... configure the `redux` store with the middleware
to prevent webpack from including up all my fixtures / fake data in the production build, while giving me a very simple way to switch between mock vs live data?
I do not want to have to eject the app, but am open to using a webpack plugin that's injected using Create React App Configuration Overrides.
I think webpack code-splitting with dynamic imports could be your best bet. This way, your mock data is bundled but never sent to the client (which I think is the main goal here).
import { apiMiddleware, createMiddleware } from 'redux-api-middleware'
const getMiddleware = async () => {
if (process.env.REACT_APP_API_URL) {
return apiMiddleware;
} else {
// loads bundle over network
const { default: fakeFetch } = await import('fixtures/utils/fakeFetch');
return createMiddleware({ fetch: fakeFetch });
}
}
I know this does not answer the question directly but on a side note, I think the cleanest way would be to utilise a mock sever such as mock-server.com. In development, you would just use the mock server url in process.env.REACT_APP_API_URL. This way, the test data lives in a completely different environment and provide a clear separation of concerns. You could probably also just create a simple local express app that just returns hardcoded JSON if you don't want to use third-party tools.

React application with external plugins

I'm building a React application bundled using Parcel or Webpack.
The application should be able to embed external React components
developed by third-parties and hosted elsewhere as modern javascript modules:
// https://example.com/scripts/hello-plugin.js
import React from 'react';
export default class HelloPlugin extends React.Component {
render() {
return "Hello from external plugin!";
}
}
Host application loads these components using asynchronous import like this, for example:
// createAsyncComponent.tsx
import * as React from 'react';
import { asyncComponent } from 'react-async-component';
export default function createAsyncComponent(url: string) {
return asyncComponent({
resolve: () => import(url).then(component => component.default),
LoadingComponent: () => <div>Loading {url}....</div>,
ErrorComponent: ({ error }) => <div>Couldn't load {url}: {error.message}</div>,
})
}
But looks like bundlers don't allow importing arbitrary urls as external javascript modules.
Webpack emits build warnings: "the request of a dependency is an expression" and the import doesn't work. Parcel doesn't report any errors, but fails when import(url) occurs at runtime.
Webpack author recommends using scriptjs or little-loader for loading external scripts.
There is a working sample that loads an UMD component from arbitrary URL like this:
public componentDidMount() {
// expose dependencies as globals
window["React"] = React;
window["PropTypes"] = PropTypes;
// async load of remote UMD component
$script(this.props.url, () => {
const target = window[this.props.name];
if (target) {
this.setState({
Component: target,
error: null,
})
} else {
this.setState({
Component: null,
error: `Cannot load component at ${this.props.url}`,
})
}
});
}
Also, I saw a similar question answered a year ago where the suggested approach also involves passing variables via a window object.
But I'd like to avoid using globals given that most modern browsers support modules out of the box.
I'm wondering if it's possible. Perhaps, any way to instruct the bundler that my import(url) is not a request for the code-split chunk of a host application, but a request for loading an external Javascript module.
In the context of Webpack, you could do something like this:
import(/* webpackIgnore: true */'https://any.url/file.js')
.then((response) => {
response.main({ /* stuff from app plugins need... */ });
});
Then your plugin file would have something like...
const main = (args) => console.log('The plugin was started.');
export { main };
export default main;
Notice you can send stuff from your app's runtime to the plugin at the initialization (i.e. when invoking main at the plugin) of the plugins so you don't end up depending on global variables.
You get caching for free as Webpack remembers (caches) that the given URL has already loaded so subsequent calls to import that URL will resolve immediately.
Note: this seems to work in Chrome, Safari & firefox but not Edge. I never bothered testing in IE or other browsers.
I've tried doing this same sort of load with UMD format on the plugin side and that doesn't seem to work with the way Webpack loads stuff. In fact it's interesting that variables declared as globals, don't end up in the window object of your runtime. You'd have to explicitly do window.aGlobalValue = ... to get something on the global scope.
Obviously you could also use requirejs - or similar - in your app and then just have your plugins follow that API.
Listen to the Webpack author. You can't do (yet) what you're trying to do with Webpack.
You will have to follow his suggested route.

React Mocha rendering, DOMException Wrong Document

Using React 13.2 and looking to test lifecyles with a setup like the one shown on this gist. If I don't stop subsequent renders (via the shouldComponentUpdate method) then anything causes a render (after the initial) explodes with a DOMException Wrong Document:
DOMException: Wrong document
at core.Node.insertBefore (D:\development\projects\fsm\node_modules\jsdom\lib\jsdom\level1\core.js:583:13)
at core.Node.insertBefore (D:\development\projects\fsm\node_modules\jsdom\lib\jsdom\level2\events.js:326:32)
at insertChildAt (D:\development\projects\fsm\node_modules\react\lib\DOMChildrenOperations.js:34:14)
at Object.DOMChildrenOperations.processUpdates (D:\development\projects\fsm\node_modules\react\lib\DOMChildrenOpertions.js:106:11)
JSDOM bails because the parent node is not a document and it don't share the same owner document as the child being inserted. Yeah. How could the owning document be anything other than that the global unless React is doing something funky under the hood.
Just surprised that I don't see more people having a similar problem? There is nothing odd-ball with my Mocha setup nor the JSX components being rendered. Plus the initial render goes fine.
Update for node 4
With node 4 we can use the latest jsdom and solve this issue in a better way, e.g. using testdom.
This is how I test a React 0.13 component with mocha on node 4:
import testDom from "testdom";
import { expect } from "chai";
testDom("<html><body></body></html>");
const React = require("react/addons");
const MyTestableComponent = require("../src/MyTestableComponent");
const ExecutionEnvironment = require("react/lib/ExecutionEnvironment");
ExecutionEnvironment.canUseDOM = true;
describe("MyTestableComponent", () => {
it("works!", () => {
const component = <MyTestableComponent />;
expect(true).to.equal(true);
})
})
Note that we should require rather than import React and the component.
Previous answer
I could fix this issue by following the OP's own comment to the question.
Since React stores the document in an internal variable when it is required, we need to remove React from the require.cache object, before requiring it again:
var jsdom = require("jsdom").jsdom;
var React, TestUtils;
describe("Example", function() {
beforeEach(function() {
// remove react from the require cache
for (var key in require.cache) {
if (key.match(/\/node_modules\/react\//)) {
delete require.cache[key];
}
}
// init the DOM
global.document = jsdom("<html><head><script></script></head><body></body></html>");
global.window = document.parentWindow;
// require react again
React = require("react/addons");
TestUtils = React.addons.TestUtils;
});
// my tests...
});

React Native + React (for web) seed project

Is it possible to setup a project which has code for both React Native(Mobile app) + React(web), having the code shred between platforms except for the UI part.
Have done something similar with Angular + NativeScript using this seed, which enables code sharing between native app and web application(Except for the UI layer). Looking for something similar for React + React Native.
Please share if you know any such seed for React Native + Angular as well, if available.
Jonathan Kaufman has a good article on how to set this up: http://jkaufman.io/react-web-native-codesharing/
The basic strategy is to have a different entry point (index.js) for each platform (android/ios/web). Then the majority of your non-rendering code can live in a shared app or common folder. You'll still need to segregate your rendering code (i.e. uses of View, div, etc.), though, as that will differ by platform.
Pay attention to the comments on that article as well, as there's some good discussion on the pitfalls of this approach. Example:
By sharing a common package.json between native and web, you've glued them together by their common dependencies, the most important one being react. Let's say you upgrade to a version of react-native that depends on >= react#16, but your web app depends on some other library which depends on =< react#15. --timtas
You can give a try to React-Native-Web, but imho you should create 2 different projects, isolate and copy what can be used on both (like api requests and util functions). Your code will be easier to debug and maintain.
Yes, absolutely possible. We've done it before using this lib react-native-web. https://github.com/necolas/react-native-web
beside index.ios.js and index.android.js, you will need create index.web.js, the content should be similar like this.
import { AppRegistry } from 'react-native';
import App from './app/Containers/App/App.container';
AppRegistry.registerComponent('ReactNativeWeb', () => App);
AppRegistry.runApplication('ReactNativeWeb', { rootTag: document.getElementById('react-app') });
also you need to create your own nodejs code to serve up the bundle. full reference
I do it this way.
1) Create a React Native project.
2) Add react-dom and react-scripts dependencies to package.json and install them.
3) All the component code is separated this way:
My regular React Native component:
// MyComponent.js
class MyComponent extends React.Component {
costructor(props) {
...
}
someMethod() {
...
}
render() {
return (
<View>
...
</View>
)
}
}
Changed for using in web:
// MyComponentController.js
class MyComponentController extends React.Component {
costructor(props) {
...
}
someMethod() {
...
}
}
// MyComponent.js
const MyComponentController = require('./MyComponentController')
class MyComponent extends MyComponentController {
render() {
return (
<div>
...
</div>
)
}
}
// MyComponent.native.js
const MyComponentController = require('./MyComponentController')
class MyComponent extends MyComponentController {
render() {
return (
<View>
...
</View>
)
}
}
And then I use in it in all the platforms:
const MyComponent = require('./MyComponent')
For this to work nicely with an old project I had to implement some dummies, but it all can be done better by your own layer of abstraction. Part of my example:
const ReactNative = {
Platform: {
OS: 'web'
},
AppRegistry: {
registerComponent: (name, provider) => {
const Component = provider()
ReactDOM.render(
<Component />,
document.getElementById('root')
);
}
},
AsyncStorage: {
setItem: (key, value, callback) => {
localStorage.setItem(key, value)
callback()
},
getItem: key => {
const val = localStorage.getItem(key) || null
return new Promise(ok => ok(val))
}
},
StyleSheet: {
create: dict => dict
},
Dimensions: {
get: function() {
// http://stackoverflow.com/questions/3437786/get-the-size-of-the-screen-current-web-page-and-browser-window
const w = window
const d = document
const e = d.documentElement
const g = d.getElementsByTagName('body')[0]
const x = w.innerWidth || e.clientWidth || g.clientWidth
const y = w.innerHeight|| e.clientHeight|| g.clientHeight
return {
width: x,
height: y
}
}
},
Linking: {
openURL: (url) => {
window.open(url)
}
},
// etc, I add dummies as soon as I need them
}
But, as I said, this was necessary only because I did not have much time and had not known in advance that I would have to port to web.
You can try the repo that I tried to prepare:
https://mehmetkaplan.github.io/react-spa-jwt-authentication-boilerplate/
This has a step by step guideline that enables to share common logic between react and react-native applications.
It aims to differentiate only in the presentation layer. Other than that all logic is compiled to be shared between applications.
It also comes with facebook and google logins, database (mysql) integration, WebView task generation, etc.
And also it gives the fundamental know-how on "single page applications", "JWT (json web token) based security", etc..
Once read the README, you can simply clone the repo and set your environment (Database) and start developing business logic on top of the shared code structure and security baseline.
You can create 3 stand-alone applications - React, React-native & Server.
Both React & React-native will use the same services from your back-end app.
Else go with a single app where on loading home page, app will understand the device and render React / React-native code as per the device.

Resources