Attempting to access a types.reference(Model) before it's id is set for mobx-state-tree? - mobx-state-tree

Got a question. So I'm making a small app working with the github api (using mobx-state-tree and mobx). I'm brand new to both.
I'm having a problem: you see selectedRepo? If i set an id to it, I can access selectedRepo. However... if I attempt to access selectedRepo before I set an id to it, the application will break. I've tried wrapping it with types.optional, types.maybe, but no matter what it just will not work.
Any ideas?
const defaultState = {
count: 10,
githubToken: "",
selectedRepo: ""
};
const Issue = types.model({
id: types.identifier(types.number),
title: types.string,
body: types.string
});
const Repo = types.model({
id: types.identifier(types.number),
name: types.optional(types.string, ""),
owner: types.optional(
types.model({
login: ""
}),
{}
)
});
const AppStore = types
.model({
state: "done",
githubToken: "",
issues: types.optional(types.array(Issue), []),
repos: types.optional(types.array(Repo), []),
selectedRepo: types.reference(Repo)
})

Related

"message": "Unexpected token < in JSON at position 0", "stack": "SyntaxError: Unexpected token < in JSON at position 0"

const express = require('express');
const {graphqlHTTP} = require('express-graphql');
const schema = require('./schema/schema');
const app = express();
app.get('/graphql', graphqlHTTP({
graphiql:true,
schema: schema
}))
app.listen(4000,()=>{
console.log("listining to port 4000..")
})
const graphql = require('graphql');
const{
GraphQLObjectType,
GraphQLID,
GraphQLString,
GraphQLInt,
GraphQLSchema
} = graphql
const UserType = new GraphQLObjectType({
name: 'user',
description: 'Documentation for User...',
fields: ()=>({
id: {type: GraphQLString},
name: {type: GraphQLString},
age: {type: GraphQLInt}
})
});
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
description: 'description',
fields: {
user: {
type: UserType,
args: {id: {type: GraphQLString}},
resolve(parent,args){
let user = {
id: '345',
age: 34,
name: 'Aman'
}
return user;
}
}
}
});
module.exports = new GraphQLSchema({
query: RootQuery
})
Above are my code and I am getting this error :
"message": "Unexpected token < in JSON at position 0",
"stack": "SyntaxError: Unexpected token < in JSON at position 0"
Can anyone tell me how I resolved this error? Thanks in advance.
This kind of seems like you're seeing this error on your client-side application? On a side note, you didn't add much details of what you're doing to get this error, where you're seeing it, and what you think is causing it, so I can only go off of what you've provided in terms of what your set up is.
This seems like you're getting an HTML response from your server where you're expecting JSON. Typically, with GraphQL this may happen because you're sending a GET request (which may bring up the GraphiQL explorer) rather than a POST request.
Your GraphQL client code should make a POST request and you should ensure that it sends a header to accept application/json responses.

drive api - write to shared folder not found

I am using google drive api to write to a folder located in shared drive.
I have created a service account and service account is added to folder with permission as 'content manager'.
However, when I try to use the api to upload file, I keep getting an error stating 'folder not found'.
The same works fine when I try to create a folder onto my personal drive and add service account with 'editor' permission.
Can someone please help me if I missed something or that is as per design?
Below is sample code snippet:
google auth:
const driveauth = new google.auth.JWT(gSuiteUser, null,
JSON.parse(gSuiteKey), [
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/drive.appdata'
])
const drive = google.drive({
version: 'v3',
auth: driveauth
});
Below is the code for uploading on google drive:
const fileMetadata = {
'name': 'Filename',
'mimeType': 'application/vnd.google-apps.spreadsheet',
parents: [gSuiteFolder],
convert: true
};
const media = {
mimeType: 'text/csv',
body: csvData
};
drive.files.create({
resource: fileMetadata,
media: media,
fields: 'id'
}, (err, file) => {
if (err) {
// Handle error
console.error(`Failure`);
callback(err);
} else {
console.log('Success', file.data.id);
callback(undefined, "done");
}
});
Turned out that we need to send additional attribute 'supportsAllDrives' as true as shown below:
drive.files.create({
resource: fileMetadata,
media: media,
supportsAllDrives: true,
fields: 'id'
}, (err, file) => {
if (err) {
// Handle error
console.error(`Failure`);
callback(err);
} else {
console.log('Success', file.data.id);
callback(undefined, "done");
}
});
I think something might be off in your deligation.
// loads credentials from .env file
require("dotenv").config();
import { google } from "googleapis";
function initializeDrive(version = "v3") {
const client_email = process.env.GOOGLE_CLIENT_EMAIL;
// add some necessary escaping so to avoid errors when parsing the private key.
const private_key = process.env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, "\n");
// impersonate an account with rights to create team drives
const emailToImpersonate = "some-user#acme-industries.com";
const jwtClient = new google.auth.JWT(
client_email,
null, // undefined if you use TypeScript
private_key,
["https://www.googleapis.com/auth/drive"],
emailToImpersonate
);
return google.drive({
version: version,
auth: jwtClient
});
}
Or maybe a bit more simple
const auth = new google.auth.JWT({ // JWT instead of GoogleAuth
subject: "me#mycompany.com", // include this property
keyFile: "service-account.json",
scopes: [ ... ],
})

Is there a way to add conversation history when connecting to direct line?

We are using botframework-webchat v4. Is there any way to provide history that will be shown up in the chat?
This is currently what I have, but its not working, not sure what format should be for activities in store.
const store = window.WebChat.createStore(
{
activities: ['{"type":"message",...}']
},
({ dispatch }: { dispatch: any }) => (next: any) => (action: any) => {
if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
const { activity } = action.payload;
if (activity.type === 'event' && activity.name === 'sample:backchannel') {
alert(JSON.stringify(activity, null, 2));
}
}
return next(action);
}
)
window.WebChat.renderWebChat(
{
directLine: this.directLine,
userID: this.userId,
styleOptions,
store
},
this.botWindowElement.nativeElement
);
Thanks in advance!!
You're solution above will, technically, work. Although, it's not very scalable in the long run. I would recommend you look over this BotFramework-WebChat experimental sample, Conversation History. It utilizes the sendConversationHistory API. This sample is a bit on the complex side, but will do precisely what you are wanting, i.e. load a previous user's conversation when a new session is started.
If you are wanting to reconnect a previous conversation (meaning continue a conversation using the same conversationId) then you should be aware that the Direct Line service has certain limitations. Reconnecting will only work for up to 14 days after the last activity to that conversation and only 24 hours if activities are present.
Hope of help!
#StevenKanberg Thanks for the help!
I found the answer in source code of BotFramework-WebChat.
Here is the sample,
test('absolute timestamp', async () => {
const activities = [
{
type: 'message',
id: '6266x5ZXhXkBfuIH0fNx0h-o|0000000',
timestamp: '2019-08-08T16:41:12.9397263Z',
from: {
id: 'dl_654b35e09ab4149595a70aa6f1af6f50',
name: '',
role: 'user'
},
textFormat: 'plain',
text: 'echo "Hello, World!"'
},
{
type: 'message',
id: '6266x5ZXhXkBfuIH0fNx0h-o|0000001',
timestamp: '2019-08-08T16:41:13.1835518Z',
from: {
id: 'webchat-mockbot',
name: 'webchat-mockbot',
role: 'bot'
},
text: 'Echoing back in a separate activity.'
},
{
type: 'message',
id: '6266x5ZXhXkBfuIH0fNx0h-o|0000002',
timestamp: '2019-08-08T16:41:13.3963019Z',
from: {
id: 'webchat-mockbot',
name: 'webchat-mockbot',
role: 'bot'
},
text: 'Hello, World!'
}
];
const styleOptions = { timestampFormat: 'absolute' };
const { driver } = await setupWebDriver({ storeInitialState: { activities }, props: { styleOptions } });

Get URL Referer [BotFramework-WebChat]

I'm using a directline inside my website and I was wondering if there is anyway to get the URL of the website inside my bot code. Previously, in v3, I was initializing the chat with:
BotChat.App({
directLine: { secret: "{directline_secret}" },
user: { id: 'You', referrer: window.location.href},
bot: { id: '{bot_id}' },
resize: 'detect'
}, document.getElementById("bot"));
and I was able to get the referrer with this line of code activity.From.Properties["referrer"].ToString(), but in v4 I can't find a way to get the referrer inside the bot.
Can someone help me?
Thanks in advance.
In v4 the value is part of the turnContext.activity (in Node) or turnContext.Activity (in C#) object. Passing the url value as you have done in your question (i.e., as part of the user object) you would access it like so (Node example):
async onTurn(turnContext) {
if (
turnContext.activity.type === "event" && turnContext.activity.name === "eventName"
) {
this.userProfile.location = turnContext.activity.from.referrer;
await console.log(this.userProfile.location);
}
I included a name as well as specified a type in my BotChat.App post to match this event to in the turnContext.activity:
function testMethod(someValue) {
botConnection
.postActivity({
from: { id: 'me', referrer: window.location.href },
name: 'eventName',
type: 'event',
value: someValue
})
.subscribe(function (id) {
console.log('"eventName" sent');
});
};
In this example, the method is tied to a button being pressed on the page.
Hope of help!

GraphQL : Implementing windowed pagination for regular list

I'm trying to implement a windowed pagination using a "List". I don't need the cursor based solution with connections, because I need to show numbered pages to the user.
There are "User" and "Post" objects."User" has one-to-many relation to "Post".
Using graphql-js for schema,
here is my schema for userType and postType:
var userType = new GraphQLObjectType({
name: 'User',
fields: () => ({
id: globalIdField('User'),
posts: {
type: new GraphQLList(postType),
args: {
page:{
type: GraphQLInt,
defaultValue: 0
}
},
resolve: (_, args) => {
//code to return relevant result set
},
},
totalPosts:{
type: GraphQLInt,
resolve: () => {
//code to return total count
}
},
}),
interfaces: [nodeInterface],
});
var postType = new GraphQLObjectType({
name: 'Post',
fields: () => ({
id: globalIdField('Post'),
name: {type: GraphQLString},
//other fields
}),
interfaces: [nodeInterface],
});
Please notice the "totalPosts" field in "userType". Since there is going to be other Lists for the user,with the same paging needs, I'm going to end up maintaining lot of "total{Type}" variables in the fragment. This can be solved if I can send the totalCount within the List result somehow.
https://github.com/facebook/graphql/issues/4 this issue talks about implementing a wrapper over the List to include the totalCount in the result set.
I tried creating a wrapper like this:
var postList = new GraphQLObjectType({
name: 'PostList',
fields:()=>({
count: {
type: GraphQLInt,
resolve: ()=>getPosts().length //this is total count
},
edges: {
type: new GraphQLList(postType),
resolve: () => {
return getPosts() ; // this is results for the page, though I don't know how to use 'page' argument here
},
}
}),
interfaces: [nodeInterface],
});
but how should I connect this to the userType's posts field? And how can I use a 'page' argument on this wrapper, like I have in original userType?
how should I connect this to the userType's posts field? And how can I use a 'page' argument on this wrapper, like I have in original userType?
One simple way to implement what you're trying to do is to define a dumb wrapper type postList like this:
var postList = new GraphQLObjectType({
name: 'PostList',
fields:()=>({
count: { type: GraphQLInt },
edges: { type: new GraphQLList(postType) }
// Consider renaming 'edges'. In your case, it's a list, not a
// connection. So, it can cause confusion in the long run.
}),
});
Then in the userType definition, add a field of that wrapper type and define its resolve function like below. As for argument page, just describe it while defining the field type posts.
posts: {
type: postList,
args: {
page:{
type: GraphQLInt,
defaultValue: 0
},
...otherArgs
},
resolve: async (_, {page, ...otherArgs}) => {
// Get posts for the given page number.
const posts = await db.getPosts(page);
// Prepare a server-side object, which corresponds to GraphQL
// object type postList.
const postListObj = {
count: posts.length,
edges: posts
};
// Consider renaming 'edges'. In your case, it's a list, not a
// connection. So, it can cause confusion in the long run.
},
},

Resources