Accessing Cookies API from a React WebExtension - reactjs

Summary
I'm trying to access the Cookies API from a WebExtension which uses React, but I don't know why, it throws a TypeException, as if browser.cookies did not exist.
I've checked permissions and the code is copy/pasted from the MDN docs... but still I can't get it to work.
Exception:
TypeError: browser.cookies is undefined
Code
This is the main component:
import React from 'react';
import ReactDOM from 'react-dom';
class Popup extends React.Component {
constructor(props) {
super(props);
this.state = { sessionId: null };
}
componentDidMount() {
var getting = browser.cookies.getAllCookieStores(); // This throws "TypeError: browser.cookies is undefined"
getting.then(logStores);
}
render() {
return (
<div>
<h1>My App</h1>
</div>
);
}
logStores(cookieStores) {
for (let store of cookieStores) {
console.log(`Cookie store: ${store.id}\n Tab IDs: ${store.tabIds}`);
}
}
}
ReactDOM.render(<Popup />, document.getElementById('app'));
And this is the manifest.json with the according permissions:
{
"manifest_version": 2,
"name": "MyApp",
"version": "1.0",
"browser_action": {
"browser_style": true,
"default_icon": {
"48": "images/Watermelon-48.png",
"96": "images/Watermelon-96.png"
},
"default_title": "MyApp",
"default_popup": "popup.html"
},
"permissions": ["browser", "cookies","<all_urls>","tabs"]
}

could you replace
"permissions": ["browser", "cookies","<all_urls>","tabs"]
By
"permissions": ["browserSettings", "cookies","<all_urls>","tabs"]

Related

Microsoft Teams Custom App doesn't work on mobile

I've already develop one custom Microsoft Teams app that correctly works on Desktop, but it doesn't work on mobile app.
It only display the page about the debug.
This is the tab into mobile app:
how can I solve it?
Thanks
This is the tab into desktop app:
This is one part of the code of my home tab for my personal app:
class Tab extends React.Component {
constructor(props) {
super(props)
this.state = {
user: null,
loading: true,
isLogged: false,
error: null,
layout: true
}
}
componentDidMount() {
const params = new URLSearchParams(this.props.location.search);
let teamsUser = {
Tid: params.get('tid'),
Aaid: params.get('aaId')
}
getUser(teamsUser).then((userResponse) => {
this.setState({
user: userResponse,
loading: false,
isLogged: true
})
}).catch((error) => {
logger.warn(JSON.stringify(error));
this.setState({
error: error,
loading: false
})
});
}
setLogged = (user) => {
this.setState({
user: user,
isLogged: true,
loading: false
})
}
render() {
let content;
const { user, loading, isLogged, error } = this.state;
if (loading) {
content = <Loading></Loading>
} else if (error) {
throw Error(error)
}
else if (isLogged) {
content = <Catalogue user={user}></Catalogue>
} else {
content = <UserLogin setLogged={this.setLogged}></UserLogin>
}
return (
<Layout>
{content}
</Layout>
);
}
}
export default Tab
and this is my manifest where I put the url with the tid and aaid:
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.9/MicrosoftTeams.schema.json",
"manifestVersion": "1.9",
"version": "1.0.0",
"id": "86af4197-14c8-4439-a440-3d33b4567f54",
"packageName": "com.microsoft.teams.extension",
"developer": {
"name": "Teams App, Inc.",
"websiteUrl": "https://localhost:3000",
"privacyUrl": "https://localhost:3000/privacy",
"termsOfUseUrl": "https://localhost:3000/termsofuse"
},
"icons": {
"color": "color.png",
"outline": "outline.png"
},
"name": {
"short": "AppLocal",
"full": ""
},
"description": {
"short": "Short description for Personal App.",
"full": "Full description of Personal App."
},
"accentColor": "#FFFFFF",
"staticTabs": [
{
"entityId": "index",
"name": "Catalogue",
"contentUrl": "https://localhost:3000/catalogue?tid={tid}&aaId={userObjectId}",
"websiteUrl": "https://localhost:3000/catalogue",
"scopes": [
"personal"
]
},
{
"entityId": "live",
"name": "Live",
"contentUrl": "https://localhost:3000/live?tid={tid}&aaId={userObjectId}",
"websiteUrl": "https://localhost:3000/live",
"scopes": [
"personal"
]
},
{
"entityId": "about",
"scopes": [
"personal"
]
}
],
"permissions": [
"identity",
"messageTeamMembers"
],
"validDomains": [
"localhost:3000",
"localhost"
]
}
I hope the above mentioned code can help you help me.
I have tested with your code and I replaced localhost URL with ngrok URL it's working fine. Running the application locally does not give you access to Teams app functionality. So could you please try with ngrok url.
I solved it, my error was in the App.js file. I had a wrong path that redirected to another page (the page published above) when try to open the url outside Microsoft Teams. I have remove it and all work's fine. Thank's for all

Invariant Violation: View config getter callback for component `Home` must be a function (received `undefined`)

I want to call the function using the key name from the array on the tab.screen component.
my code is like this:
import React from 'react';
import { Text, View, TouchableOpacity, Modal } from 'react-native';
import AsyncStorage from '#react-native-community/async-storage';
import Icon from 'react-native-vector-icons/FontAwesome5';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import Home from '../mainscreen/GeneralScreen';
import Core from '../mainscreen/CoreScreen';
import Docs from '../mainscreen/GeneralScreen';
import ESS from '../mainscreen/GeneralScreen';
import General from '../mainscreen/GeneralScreen';
import HR from '../mainscreen/GeneralScreen';
import Payroll from '../mainscreen/GeneralScreen';
import Server from '../mainscreen/CoreScreen';
const Tab = createBottomTabNavigator();
const tabcomponents = {
"Home" : Home,
"Core" : Core,
"Docs" : Docs,
"ESS" : ESS,
"General" : General,
"HR" : HR,
"Payroll" : Payroll,
"Server" : Server
};
class TabNavigator extends React.Component {
constructor() {
super();
this.state = {
dashboardtab:[],
}
this.tabnavigatorasync();
}
tabnavigatorasync = async () => {
try {
const dashboardtab = await AsyncStorage.getItem('dashboardtab');
const dashboardtabParse = JSON.parse(dashboardtab);
this.setState({dashboardtab: dashboardtabParse});
//console.log('isi dari tab navigator: ', this.state.dashboardtab);
//console.log('------------------------------------------------');
//console.log('isi dari tab navigator 2: ', this.state.dashboardtab2[0].label);
} catch (error) {
}
}
render(){
//console.log('dashboardtab', this.state.dashboardtab);
const tabnavigatorRender = this.state.dashboardtab.map((item, index) =>
const tabcomponentsrender = tabcomponents[item.admintab.label];
return <Tab.Screen name={item.admintab.label} component={tabcomponentsrender} key={index}/>
);
return(
<Tab.Navigator>
{tabnavigatorRender}
</Tab.Navigator>
)
}
}
export default TabNavigator;
the result appears an error like this:
Invariant Violation: View config getter callback for component Home must be a function (received undefined)
This is the contents of the array:
[
{
"tab_id": "home",
"order": 10,
"admintab": {
"label": "Home",
}
},
{
"tab_id": "core",
"order": 1,
"admintab": {
"label": "Core",
}
},
{
"tab_id": "docs",
"order": 2,
"admintab": {
"label": "Docs",
}
},
{
"tab_id": "ess",
"order": 50,
"admintab": {
"label": "ESS",
}
},
{
"tab_id": "general",
"order": 45,
"admintab": {
"label": "General",
}
},
{
"tab_id": "hr",
"order": 40,
"admintab": {
"label": "HR",
}
},
{
"tab_id": "payroll",
"order": 42,
"admintab": {
"label": "Payroll",
}
},
{
"tab_id": "server",
"order": 70,
"admintab": {
"label": "Server",
}
}
]
is there something wrong with the code i made?
In your case, you want to use Dynamic Component Names.
First of all import your tabs.
import Home from 'path_to_your_tab_component/Home';
import Core from 'path_to_your_tab_component/Core'; // and so on
Then pass them in the object and give them a key based on their names.
const components = {
"Home": Home
"Core": Core // and so on
}
Inside the map, create a component from this object.
const tabnavigator = this.state.dashboardtab.map((item, index) => {
const TabComponent = components[item.admintab.label];
return <Tab.Screen name={item.admintab.label} component={TabComponent} key={index}/>
});

Data version error in SPFX React -Basic Webpart

I Just created a basic spfx webpart with react but getting bellow error:
{
"resource": "/c:/Node_Dev/CRUD_React/src/webparts/crudReact001/CrudReact001WebPart.ts",
"owner": "typescript",
"code": "2611",
"severity": 8,
"message": "'dataVersion' is defined as a property in class 'BaseClientSideWebPart', but is overridden here in 'CrudReact001WebPart' as an accessor.",
"source": "ts",
"startLineNumber": 35,
"startColumn": 17,
"endLineNumber": 35,
"endColumn": 28
}
My Code:
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '#microsoft/sp-core-library';
import {
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '#microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '#microsoft/sp-webpart-base';
import * as strings from 'CrudReact001WebPartStrings';
import CrudReact001 from './components/CrudReact001';
import { ICrudReact001Props } from './components/ICrudReact001Props';
export interface ICrudReact001WebPartProps {
description: string;
}
export default class CrudReact001WebPart extends BaseClientSideWebPart<ICrudReact001WebPartProps> {
public render(): void {
const element: React.ReactElement<ICrudReact001Props> = React.createElement(
CrudReact001,
{
description: this.properties.description
}
);
ReactDom.render(element, this.domElement);
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
})
]
}
]
}
]
};
}
}
The article linked below provides more details on the issue:
https://dreamsof.dev/2020-09-21-typescript-upgrade-breaking-dataversion-get-override-spfx11/
The suggested solutions are:
Use Workspace Version for TypeScript (3.3.4000) instead of VS Code's newer version
Decorate method with // #ts-ignore
You can just delete 'datavaersion' method, it's compatible with SPFx v1.10 but will get an error when you install V1.11.

How do I iterate over a JSON file in react?

I'm new to React and for the life of me cannot figure this out.
I have a JSON file (Fontawesome icons):
{
"icons": [
{
"name": "Glass",
"id": "glass",
"unicode": "f000",
"created": 1,
"filter": [
"martini",
"drink",
"bar",
"alcohol",
"liquor"
],
"categories": [
"Web Application Icons"
]
},
{
"name": "Music",
"id": "music",
"unicode": "f001",
"created": 1,
"filter": [
"note",
"sound"
],
"categories": [
"Web Application Icons"
]
},
// etc
To start with I just want to return the name of each icon.
I've been trying to follow various tutorials and have:
import React, { PureComponent } from "react";
import iconList from './services/iconList';
export default class App extends PureComponent {
render() {
const items = iconList.map(data=>{
return(
<div>
<ul>
<li>
<span>{data.name}</span>
</li>
</ul>
</div>
)
})
return items;
}
}
But I get the error: .map is not a function.
I'm not sure what I can do differently. Each tutorial I see seems to use the map function. Is there a better/different way?
Try using
const items = iconList.icons.map(data=>{
Your data is an object with an icons property in it. You can also destructure your iconList when you import:
import {icons as iconList } from './services/iconList';

React Webcam component doesn`t work inside chrome extension

I have a problem with React Webcam - https://github.com/mozmorris/react-webcam
In desktop app everything works great - tried it with create-react-app 2.0 recently - web app starts, asks for permission to use camera and when user allows, camera starts, screenshots work, everything is fine.
However when i copy the exact same component inside our chrome extension there is a problem. When user clicks "change profile photo" the extension opens new page:
chrome-extension://ebjbbcedbjkaagbpbkdlhlnbeoehjmgn/page.html#/uploadsnapshot
The Uploadsnapshot component renders fine, no visible errors (nothing in the console), in the html there is the React-Webcam component element:
<video autoplay="" width="132" height="132" class="UploadPhotoSnapshot__webcam__3VOiZ" playsinline=""></video>
But the camera doesn`t start and no "allow / block camera" popup appears.
I searched for solutions, tried adding "audioCapture" and "videoCapture" to permissions in my "manifest.json" as mentioned here:
How to enable camera and microphone in packaged application for Chrome OS or Chrome extension?
It still will not ask for permission to use camera and will not start.
I also tried using different component: https://github.com/mabelanger/react-html5-camera-photo and got error when the component loads:
onCameraError DOMException: Invalid security origin
My component:
import React, {Component} from 'react';
import Webcam from "react-webcam";
import styles from "./UploadPhotoSnapshot.css";
class UploadPhotoSnapshot extends Component {
constructor(props) {
super(props);
this.state = {
activeImg: null,
imagesArr: []
}
}
setRef = webcam => {
this.webcam = webcam;
};
capture = () => {
let shot = this.webcam.getScreenshot();
let newArr = [...this.state.imagesArr];
newArr.unshift(shot);
this.setState({
activeImg: shot,
imagesArr: newArr
});
};
render() {
const videoConstraints = {
width: 132,
height: 132,
facingMode: "user"
};
let imagesPreview = null;
if (this.state.imagesArr.length > 0) {
imagesPreview = (
<div className={styles.webcamArrScroll}>
{this.state.imagesArr.map((image, index) => (
<img className={styles.webcamArrImg} src={image} alt="" key={index} />
))}
</div>
);
}
return (
<div className={styles.webcamDiv}>
<Webcam
audio={false}
height={132}
ref={this.setRef}
screenshotFormat="image/jpeg"
width={132}
videoConstraints={videoConstraints}
className={styles.webcam}
/>
<button className={styles.webcamBtnTakePhoto} onClick={this.capture}>Take a snapshot</button>
<div className={styles.webcamArr}>
{imagesPreview}
</div>
<div className={styles.buttons}>
<button className={styles.buttonText}>Cancel</button>
<button className={styles.buttonSetPhoto} onClick={this.hasFileUploaded}>Set a profile photo</button>
</div>
</div>
);
}
}
export default UploadPhotoSnapshot;
my manifest.json:
{
"manifest_version": 2,
"name": "DEV",
"description": "dev",
"version": "4.0.0",
"content_security_policy": "script-src 'self' 'unsafe-eval' https://ssl.google-analytics.com https://apis.google.com https://www.google-analytics.com; object-src 'self'",
"default_locale": "en",
"background": {
"scripts": ["background.js"]
},
"browser_action": {
"default_icon": "/icons/icon_48.png",
"default_popup": "index.html"
},
"icons": {
"16": "/icons/icon_16.png",
"32": "/icons/icon_32.png",
"48": "/icons/icon_48.png",
"64": "/icons/icon_64.png",
"128": "/icons/icon_128.png"
},
"web_accessible_resources": [
"app/*",
"/images/*",
"favicon.ico"
],
"sandbox": {
"pages": ["page.html"]
},
"commands": {
"_execute_browser_action": {
"suggested_key": {
"default": "Alt+P"
}
}
},
"permissions": [
"tabs",
"storage",
"identity",
"audioCapture",
"videoCapture",
"identity.email"
],
"oauth2": {
"client_id": "12345.apps.googleusercontent.com",
"scopes": [
"email",
"profile",
"https://www.googleapis.com/auth/contacts.readonly"
]
},
"key": "12345"
}
Do i somehow have to invoke the "allow / deny camera" popup inside the Chrome extension component?
Would be very gratefull for any ideas/ help / hint / solutions.
This might be related to this Chromium bug that makes the extension crash (although you don't get exactly the same error).
See a solution for a possible duplicate here: Chrome Extension - getUserMedia throws "NotAllowedError: Failed due to shutdown"
I found the problem and fixed it.
It all came down to "sandbox": {
"pages": ["page.html"]
}, in the manifest.json file. When you use "sandbox", the content security origin is blocking everything. I deleted it and everything is working. Camera, sound recording, screenshots.

Resources