update observable object from array in observable object - arrays

I have documents id in the Information I am getting from service. I need documents Info to be attached to this parent information and return parent. Not able to return observables in loop.
The second switch map is working fine. The first is not executing if I return tInfo from map, it gives following error below.
Argument of type '(tInfo: { documents; documentsInfo:
any[]; }) => void' is not assignable to parameter of type '(value:
{ documents: any; documentsInfo: any[]; }, index: number) =>
ObservableInput'. Type 'void' is not assignable to type
'ObservableInput'
public transform(tId: any,name: string, args?: any): Observable<string> {
return this.sService.getTaxById(tId).pipe(
// tslint:disable-next-line: deprecation
switchMap((tInfo:{ documents ; documentsInfo: any [] }) => {
if (tInfo.documents) {
tInfo..documents.forEach(doc => {
return this.sService
.getFiles(doc.docId).pipe(
map((filesInfo: { FileName: ''; downloadUrl: '' }) => {
const fileObjnew =
{
docName: filesInfo.FileName,
downloadUrl: filesInfo.downloadUrl,
}
tInfo.documentsInfo.push(fileObjnew);
})
);
});
return of(taxInfo);
}
}),
// tslint:disable-next-line: deprecation
switchMap((Info: { cc: '' ; authority: '' ; cName: ''}) => {
if (Info.authority) {
const cc = taxInfo.cc;
return this.sService.getOrgs(cc).pipe(
map((orgsData: any) => {
console.log("Data============>", orgsData);
(orgsData || []).forEach(tax => {
if (orgsData.aid === tax.id) {
Info.cName = tax.parentName;
}
});
return Info;
})
);
}
}),
map((Info) => {
if (name === 'subsTemplate') {
return this.subsTemplate(Info);
}
})
);
}

In the first switchMap you have to return an observable in all code paths and to chain the getFiles sub-observables to your main observable, then return the observable combined by forkJoin.
You can try the following:
public transform(tId: any, name: string, args?: any): Observable<string> {
return this.sService.getTaxById(tId).pipe(
// tslint:disable-next-line: deprecation
switchMap((tInfo: { documents; documentsInfo: any[] }) => {
if (tInfo.documents) {
return forkJoin(
tInfo.documents.map((doc) =>
this.sService.getFiles(doc.docId).pipe(
map((filesInfo: { FileName: ''; downloadUrl: '' }) => {
const fileObjnew = {
docName: filesInfo.FileName,
downloadUrl: filesInfo.downloadUrl,
};
tInfo.documentsInfo.push(fileObjnew);
})
)
)
).pipe(mapTo(taxInfo));
}
return of(taxInfo);
}),
// tslint:disable-next-line: deprecation
switchMap((Info: { cc: ''; authority: ''; cName: '' }) => {
if (Info.authority) {
const cc = taxInfo.cc;
return this.sService.getOrgs(cc).pipe(
map((orgsData: any) => {
console.log('Data============>', orgsData);
(orgsData || []).forEach((tax) => {
if (orgsData.aid === tax.id) {
Info.cName = tax.parentName;
}
});
return Info;
})
);
}
return of(null);
}),
map((Info) => {
if (name === 'subsTemplate') {
return this.subsTemplate(Info);
}
})
);
}

Related

SPFx React Component Property Pane Update Lag

EDITED WITH CORRECT ANSWER
So I am customizing an SPFx component's property pane with a PropertyFieldSitePicker and a PropertyFieldListPicker. My issue is that the PropertyFieldMultiSelect lags by one selection when I select options from the PropertyFieldListPicker menu. However, if I make selections it will then update making me suspect it is a React state issue.
In the code below the following is the code logic
PropertyFieldListPicker('lists', {
// ... more props
onPropertyChange: this.onPropertyPaneFieldChanged.bind(this),
}),
then
protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
if (newValue !== oldValue && propertyPath === 'lists') {
this.loadPropertyPaneResources()
}
}
then
// this gets modified by loadPropertyPaneResources below
private _locationOptions: [];
protected loadPropertyPaneResources(): Promise<void> {
let listUrl = `...`
//... more code
return new Promise((resolve, reject) => {
this.context.spHttpClient.get(listUrl, SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => response.json())
.then((responseJSON: any) => {
this._locationOptions = responseJSON.value.map(item => {
if (item.displayName) {
return { key: item.Id, text: item.displayName }
}
return { key: item.Id, text: item.Title }
})
this.context.propertyPane.refresh()
resolve()
})
// ... more code
});
}
then
PropertyFieldMultiSelect('selectedLocations', {
key: 'selectedLocations',
label: 'Select Office Locations',
options: this._locationOptions, // from loadPropertyPaneResources above
selectedKeys: this.properties.selectedLocations
}),
FULL COMPONENT CLASS
export default class WorldClockWebPart extends BaseClientSideWebPart<IWorldClockProps> {
private _themeProvider: ThemeProvider
private _themeVariant: IReadonlyTheme | undefined
private _locationOptions: []
private _handleThemeChangedEvent(args: ThemeChangedEventArgs): void {
this._themeVariant = args.theme
this.render()
}
protected loadPropertyPaneResources(): Promise<void> {
let listUrl = `${this.context.pageContext.web.absoluteUrl}/_api/lists/GetByTitle('World Clock Locations')/items`;
const { sites, lists } = this.properties
if (sites && sites[0] && sites[0].url && lists) {
listUrl = `${sites[0].url}/_api/lists(guid'${lists}')/items`;
}
return new Promise((resolve, reject) => {
this.context.spHttpClient.get(listUrl, SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => response.json())
.then((responseJSON: any) => {
this._locationOptions = responseJSON.value.map(item => {
if (item.displayName) {
return { key: item.Id, text: item.displayName }
}
return { key: item.Id, text: item.Title }
});
resolve();
})
.catch(error => {
console.error(error);
resolve();
});
});
}
protected onInit(): Promise<void> {
// Consume the new ThemeProvider service
this._themeProvider = this.context.serviceScope.consume(ThemeProvider.serviceKey)
// If it exists, get the theme variant
this._themeVariant = this._themeProvider.tryGetTheme()
// Register a handler to be notified if the theme variant changes
this._themeProvider.themeChangedEvent.add(this, this._handleThemeChangedEvent)
return super.onInit()
}
public render(): void {
const element: React.ReactElement<IWorldClockProps> = React.createElement(
WorldClock,
{
title: this.properties.title,
context: this.context,
displayMode: this.displayMode,
titlePlaceholder: this.properties.titlePlaceholder,
themeVariant: this._themeVariant,
updateProperty: (value: string) => {
this.properties.title = value
},
locations: [],
seeMoreUrl: this.properties.seeMoreUrl,
selectedLocations: this.properties.selectedLocations,
sites: this.properties.sites,
lists: this.properties.lists, // Stores the list ID(s)
}
)
ReactDom.render(element, this.domElement)
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement)
}
protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
if (newValue !== oldValue && propertyPath === 'lists') {
this.loadPropertyPaneResources()
}
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription,
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('seeMoreUrl', {
label: 'See More URL',
}),
PropertyFieldMultiSelect('selectedLocations', {
key: 'selectedLocations',
label: 'Select Office Locations',
options: this._locationOptions,
selectedKeys: this.properties.selectedLocations
}),
PropertyFieldSitePicker('sites', {
label: 'Select sites',
initialSites: this.properties.sites,
context: this.context,
deferredValidationTime: 500,
multiSelect: false,
onPropertyChange: this.onPropertyPaneFieldChanged,
properties: this.properties,
key: 'sites'
}),
PropertyFieldListPicker('lists', {
label: 'Select a list',
selectedList: this.properties.lists,
includeHidden: false,
orderBy: PropertyFieldListPickerOrderBy.Title,
disabled: false,
onPropertyChange: this.onPropertyPaneFieldChanged.bind(this),
properties: this.properties,
context: this.context,
onGetErrorMessage: null,
deferredValidationTime: 0,
key: 'listPickerFieldId',
webAbsoluteUrl: this.properties.sites[0].url
}),
],
},
],
},
],
}
}
protected get dataVersion(): Version {
return Version.parse('1.0')
}
}
References:
https://pnp.github.io/sp-dev-fx-property-controls/controls/PropertyFieldListPicker/
https://pnp.github.io/sp-dev-fx-property-controls/controls/PropertyFieldMultiSelect/
https://pnp.github.io/sp-dev-fx-property-controls/controls/PropertyFieldSitePicker/
I needed to call this.context.propertyPane.refresh() before I resolve the promise in loadPropertyPaneResources.

How to test component using spyFn in React Jest

I want to test my component Actions when I pass actions to children. In a nutshell, every source like twitter or facebook has its own set of actions. I'd like to check that it is called or not using spy.
This is my Actions component
const targetMetric = 'account dropdown'
const availableActions = {
addQuery: {
facebook: '^facebook://page/',
twitter: true
},
exclude: {
blog: [
'^blog://user/eventregistry/',
'^eventregistry://user/'
],
news: [
'^news://user/eventregistry/',
'^eventregistry://user/'
],
twitter: true,
youtube: true
},
reportAsNews: {
youtube: true,
mastodon: true,
twitter: true
}
}
const requiredHandlers = {
exclude: [
'onExcludeProfile'
],
reportAsNews: [
'onReportAsNews'
]
}
class Actions extends React.PureComponent {
get actions() {
const { account, handlers } = this.props
const actions = {};
Object.keys(availableActions).forEach(key =>
actions[ key ] = false
)
Object.keys(actions).forEach(key => {
const value = (
!!account.uri
&&
availableActions[ key ][ account.type ]
)
if (!value) {
return
}
if (typeof value === 'boolean') {
actions[ key ] = value
return
}
if (typeof value === 'string') {
const re = new RegExp(value, 'i')
actions[ key ] = re.test(account.uri)
return
}
if (
typeof value === 'object'
&&
Array.isArray(value)
) {
actions[ key ] = value.some(v => {
const re = new RegExp(v, 'i')
return re.test(account.uri)
})
}
})
Object.keys(actions).forEach(key => {
if (!actions[ key ] || !requiredHandlers[ key ]) {
return
}
actions[ key ] = requiredHandlers[ key ].some(i => handlers[ i ])
})
if (actions.addQuery) {
actions.addQuery = Object
.keys(this.addQueryActions)
.some(key => this.addQueryActions[ key ])
}
return actions
}
get addQueryActions() {
const { availableLanguages = [], userIsAdmin } = this.context
const { caseItem, handlers } = this.props
const actions = {
addQueryToFilter: !caseItem.isPaused && !!handlers.onAddQuery,
addQueryToAccountList: userIsAdmin && !!handlers.onAddToAccountList
}
actions.addQueryToSearch = actions.addQueryToFilter && !!availableLanguages.length
return actions
}
get actor() {
return pick(
this.props.account,
[ 'uri', 'name', 'link' ]
)
}
onExclude = () => {
const { account, handlers, isCaseLocked } = this.props
if (isCaseLocked) {
return
}
handlers.onExcludeProfile(account)
}
onReportAsNews = () => this.props.handlers.onReportAsNews(this.actor)
onAddToAccountList = () => {
const { account, from, handlers } = this.props
handlers.onAddToAccountList(account, from)
}
onAddToQuery = type => ({ language } = {}) => {
const { account, caseItem, handlers } = this.props
const { id } = caseItem
const metrics = {
index: getId(),
language,
type
}
handlers.onAddQuery({
...metrics,
expression: this.expressionFromAccount(account),
hideSearch: true,
id,
})
return metrics
}
expressionFromAccount = account => ({
and: [
{ account }
]
})
trackExcludeEvent = () => {
const { account } = this.props
this.trackEvent(
events.excludeAccounts,
{
accountsAdded: 1,
source: account.type
}
)
}
trackCreateNewQueryEvent = ({ index, language, type }) => {
const eventNameMap = {
filters: events.createNewFilter,
queries: events.createNewSearch,
}
const metrics = {
queryId: index,
target: targetMetric
}
if (type === 'queries') {
metrics[ 'language' ] = language.toLowerCase()
}
this.trackEvent(
eventNameMap[ type ],
metrics
)
}
trackReportAsNewsEvent = () => (
this.trackEvent(
events.reportAsNews,
{ source: this.props.account.type }
)
)
trackEvent = (eventName, props = {}) => {
const { from, message } = this.props
eventTracker.track(
eventName,
{
...props,
from,
messageUri: message.uri
}
)
}
getLangMenuActions = ({ handlers, isCaseLocked }, { availableLanguages }) => {
if (
isCaseLocked
||
!availableLanguages
||
!handlers.onAddQuery
) {
return []
}
const onClick = compose(
this.trackCreateNewQueryEvent,
this.onAddToQuery('queries')
)
return availableLanguages.map(({ label, value: language }) => ({
handler: onClick.bind(this, { language }),
id: `add-account-to-search-lang-${language}`,
label
}))
}
getActions = () => {
const { isCaseLocked } = this.props
const { userIsAdmin } = this.context
const actions = []
if (this.actions.addQuery) {
const addQueryAction = {
id: 'add-account-to',
isInactive: isCaseLocked && !userIsAdmin,
label: i18n.t('SOURCES.DROPDOWN_ADD_TO'),
children: []
}
if (this.addQueryActions.addQueryToSearch) {
addQueryAction.children.push({
id: 'add-account-to-search',
isInactive: isCaseLocked,
label: i18n.t('SOURCES.DROPDOWN_NEW_SEARCH'),
children: this.getLangMenuActions(this.props, this.context)
})
}
if (this.addQueryActions.addQueryToFilter) {
addQueryAction.children.push({
handler: compose(
this.trackCreateNewQueryEvent,
this.onAddToQuery('filters')
),
id: 'add-account-to-filter',
isInactive: isCaseLocked,
label: i18n.t('SOURCES.DROPDOWN_NEW_FILTER')
})
}
if (this.addQueryActions.addQueryToAccountList) {
addQueryAction.children.push({
handler: this.onAddToAccountList,
id: 'add-account-to-account-list',
label: i18n.t('SOURCES.DROPDOWN_ACCOUNT_LIST')
})
}
actions.push(addQueryAction)
}
if (this.actions.reportAsNews) {
actions.push({
handler: compose(
this.onReportAsNews,
this.trackReportAsNewsEvent
),
id: 'report-as-news',
label: i18n.t('SOURCES.DROPDOWN_REPORT_AS_NEWS')
})
}
if (this.actions.exclude) {
actions.push({
handler: compose(
this.onExclude,
this.trackExcludeEvent
),
id: 'exclude-account',
isInactive: isCaseLocked,
label: i18n.t('SOURCES.DROPDOWN_EXCLUDE')
})
}
console.log(actions)
return actions
}
render() {
return this.props.children({
actions: this.getActions()
})
}
}
This is my test file
import expect from 'expect'
const injectActions = require('inject-loader!./actions')
const Actions = injectActions({
'cm/common/event-tracker': {
eventTracker: {
track: () => {},
clear: () => {}
},
events: {
createNewFilter: '...',
createNewSearch: '...',
excludeAccounts: '...',
reportAsNews: '...',
}
},
}).default
const handlers = {
onAddQuery: () => { },
onAddToAccountList: () => { },
onExcludeProfile: () => { },
onReportAsNews: () => { }
}
const testProps = {
twitter: {
account: {
name: 'Twitter account',
uri: 'twitter://status/12345',
type: 'twitter'
},
handlers,
},
facebookPage: {
account: {
name: 'Facebook page account',
uri: 'facebook://page/12345',
type: 'facebook'
},
handlers
}
}
describe('Actions component', () => {
let node
beforeEach(() => {
node = document.createElement('div')
})
afterEach(() => {
ReactDOM.unmountComponentAtNode(node)
})
it('returns empty actions array by default', () => {
const spyFn = expect.createSpy().andReturn(null)
ReactDOM.render(
<Actions>{spyFn}</Actions>,
node
)
expect(spyFn).toHaveBeenCalledWith({ actions: [] })
})
describe('Twitter', () => {
it('returns "Exclude" action', () => {
const { account, handlers } = testProps.twitter
const spyFn = expect.createSpy()
ReactDOM.render(
<Actions
account={account}
handlers={{
onExcludeProfile: handlers.onExcludeProfile
}}
isCaseLocked={false}
>
{spyFn}
</Actions>,
node
)
expect(spyFn).toHaveBeenCalledWith({ actions: [
{
handler: () => {},
id: 'exclude-account',
isInactive: false,
label: 'Exclude',
}
] })
})
})
First unit case works fine, but the second is wrong. Actually I don't need all object there too. I'd like to be only sure that it contains id: 'exclude-account' there.
Please guys about any help.
You can use expect.objectContaining(object)
matches any received object that recursively matches the expected properties
E.g.
describe('68770432', () => {
test('should pass', () => {
const spyFn = jest.fn();
spyFn({
actions: [{ handler: () => {}, id: 'exclude-account', isInactive: false, label: 'Exclude' }],
});
expect(spyFn).toBeCalledWith({
actions: [
expect.objectContaining({
id: 'exclude-account',
}),
],
});
});
});

React data do not appears on the screen

what am I doing wrong
I'm making a rest request but I'm not getting the data
I'm having the 403 error
is there any parameter missing
I tested the api on insomnia and it's working
the data appears on the console but does not appear on the screen
Code API below
How can I Solve this?
I am New With React
import axios from 'axios';
import Utils from '../atendimento/utils';
const URL = `${Utils.ngrok_service}/protocol/generate`;
const protocolGet = (clientCode, _success, _error) => {
if (!!clientCode) {
const options = {
headers: { 'Content-Type': 'application/json;charset=UTF-8' },
};
const Code = {
codigoCliente: String(clientCode).split(' ').join(''),
};
axios
.post(URL, Code, options)
.then((response) => {
const data = response.data;
if (Object.keys(data).length > 0) {
if (typeof _success === 'function') _success(data);
} else {
if (typeof _error === 'function') {
_error({
code: 404,
message: 'Falha ao gerar um protocolo.',
});
}
}
})
.catch((error) => {
if (typeof _error === 'function') {
_error({
code: 400,
message: 'Falha ao gerar um protocolo.',
});
}
});
}
};
export default protocolGet;
Code JSX Bellow:
class SelectTabs extends Component {
constructor ( props ) {
super( props );
this.state = {
options: [],
cusProtocol:"",
isReady: false
};
this.loadTabs = this.loadTabs.bind( this );
this.makeOptions = this.makeOptions.bind( this );
}
componentDidMount ( ) {
console.log('[SelectTabs] rendered with props: ', this.props );
this.loadTabs();
}
loadTabs ( ) {
protocolGet( "123245",cusProtocol => {
console.log('[SelectProtocol] cusProtocol: ', cusProtocol );
this.setState({ cusProtocol });
}, error => {
console.log('[SelectProtocol] Não foi possível consultar o serviço: ');
console.log( error );
});
tabGet( options => {
console.log('[SelectTabs] options: ', options );
this.setState({ options });
}, error => {
console.log('[SelectTabs] Não foi possível consultar o serviço: ');
console.log( error );
});
}
makeOptions ( object ) {
const options = object.map( data => {
return {
value: data,
label: data
}
});
return options;
}
render ( ) {
const $Task = this.props.task;
const selectProps = {
isRtl: false,
isMulti: false,
isClearable: false,
isSearchable: false,
placeholder: 'Selecione',
noOptionsMessage: () => 'Aguarde...'
};
return (
<React.Fragment>
<SC.Container>
<SC.Title>Protocolo</SC.Title>
<SC.Input>
<TextareaAutosize disabled type="text" value={
this.state.cusProtocol
}/>
</SC.Input>
<SC.Title>Tabulação</SC.Title>
<Select
{ ...selectProps }
options={ this.makeOptions( this.state.options ) }
onChange={ event => {} }
/>
</SC.Container>
</React.Fragment>
);

Office UI Fabric React people picker not populating suggested drop down

When I'm using the office ui fabric react component for people picker, it's not populating the suggested people in the dropdown.
Two errors that I'm getting are
Exception in CommandButton.render(): TypeError: Cannot read property 'palette' of undefined
and
Exception in Layer.componentDidUpdate(): Exception in CommandButton.render(): TypeError: Cannot read property 'palette' of undefined
I've only been able to find this issue on github https://github.com/OfficeDev/office-ui-fabric-react/issues/1952, but there isn't much to go on. I am using office-ui-fabric-react version 4.5.1
The query is working from what I can see because I can console.log the results and it has people in there.
Here's what it looks like right now.
import * as React from 'react';
import { css,} from 'office-ui-fabric-react';
import { IReactRequestProps } from './IReactRequestProps';
import {
CompactPeoplePicker,
IBasePickerSuggestionsProps,
ListPeoplePicker,
NormalPeoplePicker
} from 'office-ui-fabric-react/lib/Pickers';
import { IPersonaProps } from 'office-ui-fabric-react/lib/Persona';
const suggestionProps: IBasePickerSuggestionsProps = {
suggestionsHeaderText: 'Suggested People',
noResultsFoundText: 'No results found',
loadingText: 'Loading'
};
import {
BaseComponent,
assign,
autobind
} from 'office-ui-fabric-react/lib//Utilities';
import { people } from './PeoplePickerExampleData';
import { Label } from 'office-ui-fabric-react/lib/Label';
import { IPeopleDataResult } from './IPeopleDataResult';
import { IPersonaWithMenu } from 'office-ui-fabric-react/lib/components/pickers/PeoplePicker/PeoplePickerItems/PeoplePickerItem.Props';
import { IContextualMenuItem } from 'office-ui-fabric-react/lib/ContextualMenu';
import { SPHttpClient, SPHttpClientResponse } from '#microsoft/sp-http';
export interface IOfficeUiFabricPeoplePickerState {
currentPicker?: number | string;
delayResults?: boolean;
}
export interface IPeopleSearchProps {
JobTitle: string;
PictureURL: string;
PreferredName: string;
}
export default class ReactRequest extends React.Component<IReactRequestProps, IOfficeUiFabricPeoplePickerState> {
private _peopleList;
private contextualMenuItems: IContextualMenuItem[] = [
{
key: 'newItem',
icon: 'circlePlus',
name: 'New'
},
{
key: 'upload',
icon: 'upload',
name: 'Upload'
},
{
key: 'divider_1',
name: '-',
},
{
key: 'rename',
name: 'Rename'
},
{
key: 'properties',
name: 'Properties'
},
{
key: 'disabled',
name: 'Disabled item',
disabled: true
}
];
constructor() {
super();
this._peopleList = [];
people.forEach((persona: IPersonaProps) => {
let target: IPersonaWithMenu = {};
assign(target, persona, { menuItems: this.contextualMenuItems });
this._peopleList.push(target);
});
this.state = {
currentPicker: 1,
delayResults: false
};
}
public render(): React.ReactElement<IReactRequestProps> {
if (this.props.typePicker == "Normal") {
return (
<NormalPeoplePicker
onResolveSuggestions={this._onFilterChanged}
getTextFromItem={(persona: IPersonaProps) => persona.primaryText}
pickerSuggestionsProps={suggestionProps}
className={'ms-PeoplePicker'}
key={'normal'}
/>
);
} else {
return (
<CompactPeoplePicker
onResolveSuggestions={this._onFilterChanged}
getTextFromItem={(persona: IPersonaProps) => persona.primaryText}
pickerSuggestionsProps={suggestionProps}
className={'ms-PeoplePicker'}
key={'normal'}
/>
);
}
}
#autobind
private _onFilterChanged(filterText: string, currentPersonas: IPersonaProps[], limitResults?: number) {
if (filterText) {
if (filterText.length > 2) {
return this.searchPeople(filterText, this._peopleList);
}
} else {
return [];
}
}
private searchPeople(terms: string, results: IPersonaProps[]): IPersonaProps[] | Promise<IPersonaProps[]> {
//return new Promise<IPersonaProps[]>((resolve, reject) => setTimeout(() => resolve(results), 2000));
return new Promise<IPersonaProps[]>((resolve, reject) =>
this.props.spHttpClient.get(`${this.props.siteUrl}/_api/search/query?querytext='*${terms}*'&rowlimit=10&sourceid='b09a7990-05ea-4af9-81ef-edfab16c4e31'`,
SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
}
})
.then((response: SPHttpClientResponse): Promise<{ PrimaryQueryResult: IPeopleDataResult }> => {
return response.json();
})
.then((response: { PrimaryQueryResult: IPeopleDataResult }): void => {
let relevantResults: any = response.PrimaryQueryResult.RelevantResults;
let resultCount: number = relevantResults.TotalRows;
let people = [];
let persona: IPersonaProps = {};
console.log(relevantResults);
console.log('really relevant');
if (resultCount > 0) {
relevantResults.Table.Rows.forEach(function (row) {
row.Cells.forEach(function (cell) {
//person[cell.Key] = cell.Value;
if (cell.Key === 'JobTitle')
persona.secondaryText = cell.Value;
if (cell.Key === 'PictureURL')
persona.imageUrl = cell.Value;
if (cell.Key === 'PreferredName')
persona.primaryText = cell.Value;
});
people.push(persona);
});
}
resolve(people);
console.log(people);
console.log("PEOPLE");
}, (error: any): void => {
reject(this._peopleList = []);
}));
}
private _filterPersonasByText(filterText: string): IPersonaProps[] {
return this._peopleList.filter(item => this._doesTextStartWith(item.primaryText, filterText));
}
private _removeDuplicates(personas: IPersonaProps[], possibleDupes: IPersonaProps[]) {
return personas.filter(persona => !this._listContainsPersona(persona, possibleDupes));
}
private _listContainsPersona(persona: IPersonaProps, personas: IPersonaProps[]) {
if (!personas || !personas.length || personas.length === 0) {
return false;
}
return personas.filter(item => item.primaryText === persona.primaryText).length > 0;
}
private _filterPromise(personasToReturn: IPersonaProps[]): IPersonaProps[] | Promise<IPersonaProps[]> {
if (this.state.delayResults) {
return this._convertResultsToPromise(personasToReturn);
} else {
return personasToReturn;
}
}
private _convertResultsToPromise(results: IPersonaProps[]): Promise<IPersonaProps[]> {
return new Promise<IPersonaProps[]>((resolve, reject) => setTimeout(() => resolve(results), 2000));
}
private _doesTextStartWith(text: string, filterText: string): boolean {
return text.toLowerCase().indexOf(filterText.toLowerCase()) === 0;
}
}
i got that error when using later versions of fabric. works fine with older versions,

Error: UserCreatePayload.viewer field type must be Output Type but got: undefined

The code below works when the entire schema is in a single file, but I'm getting the above error when I try to split it into individual files.
I'm importing all the types and functions.
I have to add more details, but I'm not sure what to say. I think it's a sequencing problem since it works in a single file, but not split up.
Thanks a lot.
const UserCreateMutation = mutationWithClientMutationId({
name: 'UserCreate',
inputFields: {
email: {type: new GraphQLNonNull(GraphQLString)},
password: {type: new GraphQLNonNull(GraphQLString)}
},
outputFields: {
viewer: {
type: viewerType,
resolve() {
return viewerGet();
}
},
field: {
type: userType,
resolve(node) {
return node;
}
}
},
async mutateAndGetPayload({email, password}, {db, req}) {
export const viewerType = new GraphQLObjectType({
name: 'Viewer',
fields() {
return {
id: globalIdField('Viewer', ({_id: viewerLocalId}) => {
return viewerLocalId;
}),
_id: {type: GraphQLID},
user: {
type: userType,
resolve(parent, args, {req: {user}}) {
return user || {};
}
},
profile: {
type: profileConnectionType,
args: {
id: {type: GraphQLID},
searchTerm: {type: GraphQLString},
...connectionArgs
},
resolve(parent, {id: profileGlobalId, searchTerm, ...connectionArgs}, {db}) {
const query = (() => {
const q = {};
if (profileGlobalId) {
const {id: profileLocalId} = fromGlobalId(profileGlobalId);
Object.assign(
q,
{_id: new ObjectID(profileLocalId)}
);
}
if (searchTerm) {
Object.assign(
q,
{
$text: {
$search: `\"${searchTerm}\"`
}
}
);
}
return q;
})();
const sort = {_id: -1};
const limit = 0;
return connectionFromPromisedArray(
promisedArrayGet(
query,
sort,
limit,
profileCollectionName,
db
),
connectionArgs
);
}
}
};
},
interfaces: [nodeInterface]
});
class Viewer extends Object {}
export const viewerGet = () => {
return Object.assign(
new Viewer(),
{
_id: 'Viewer'
}
);
};
import { viewerType, userType, viewerGet }
Not sure if this is the problem but sometimes module-loading order is an issue. If it is the problem, you can solve it by making outputFields a thunk, i.e. a function that returns the object instead of a plain object.
outputFields: () => ({
viewer: {
type: viewerType,
resolve() {
return viewerGet();
}
},
field: {
type: userType,
resolve(node) {
return node;
}
}
}),

Resources