User Profile
Cardinal_Night
Brass Contributor
Joined 7 years ago
User Widgets
Recent Discussions
Disabling Move or Copy for SharePoint Libs
Is there a way to hide the Move or Copy feature in a SharePoint Lib for SPO? Would using SPFX extension allow you to hide it? I know that Restricted removes Copy and Move but this permission level not always adequate for our business use.450Views0likes0CommentsSetting SharePoint Online permissions using SPFX and it's limitations
I've been developing SPFX webparts and come up against an issue when trying to set permissions. I knew that a user without Full Control permissions, cannot change permissions on a securable (SPO list item or file). This I foolishly realised, after many weeks of developing using the SPFX workbench, only to deploy a version to a real site, sign in as a user without Full Control, attempt to create a list item or file only for it to give back 403 errors, forbidden or access denied when the item is created and the pnp/sp kicks in (for e.g.): const ReadroleDefinition = await sp.web.roleDefinitions.getByName("Read").get(); await sp.web.lists.getByTitle('Attachments').items.getById(theId).breakRoleInheritance(true, true); if(DeptContact){ await sp.web.lists.getByTitle('Attachments').items.getById(theId).roleAssignments.add(DeptContact, ReadroleDefinition.Id); } I elevated the users permissions incrementally, from Contribute, to Edit, to Design, none worked until finally I increased it to Full Control. This allowed the user to work with the form as normal. The big problem this caused though was that user had full control. Which for the customer was far too much power! My question: Is there a way to create a webpart/extension using pnp/sp that can change permissions on an item/file without the user needing Full Control?3.4KViews0likes0CommentsRe: Increase size of workarea on SPFX Workbench.aspx
mujassir Where do you add it in the scss file? Encompassing all other elements? or just at the top? It's not working for me, it doesn't accept :global for a start, if I change it to .global it does, but still, doesn't work for me. Update: keeping the code as Mujassir suggests, DOES work on spfx. This is a much quicker solution. Well done.6.4KViews1like0CommentsRe: Increase size of workarea on SPFX Workbench.aspx
Joel Rodrigues Getting error when bundling: Error: JSON validation failed: C:\Users\me\developer\sp-dev-fx-webparts\samples\js-workbench-customizer\config\package-solution.json Error: #/solution Additional properties not allowed: developer at .... (loads more locations in node modules here). developer is the folder I keep all projects in btw6.5KViews0likes0CommentsRe: Increase size of workarea on SPFX Workbench.aspx
Waqar Muneer This doesn't make the workbench placeholder bigger it only makes the container bigger using scss. If you make the container bigger than the workbench it the sides of the container will disappear, which is no good. If you know of a way to make the workbench place holder bigger then please do share.6.6KViews0likes4CommentsHow to use the return value from FilePicker to add to a SharePoint list item attachment, using @pnp
I'm getting this error when using the below to submit to a SharePoint list item as an attachment. I'm using this method: const { filePicked } = this.state; if (filePicked) { let targetList: IList = sp.web.lists.getByTitle('PanelMeetings'); let selectedFile = filePicked.downloadFileContent(); let reader = new FileReader(); reader.readAsArrayBuffer(selectedFile); reader.onload = () => { targetList.items.getById(r.data.Id).attachmentFiles.add(filePicked.fileName, reader.result); this.setState({ message: 'Attachment Successfully added' }); }; } I've read this: https://en.it1352.com/article/fe83588ba22a46fa8c16676cc29ec66a.html But it's not detailing the exact problem comprehensively enough. Can someone tell me what I'm doing wrong here?1.7KViews0likes0CommentsHow would I update list item attachments using pnp js?
I'm trying to find how to create a file upload feature for an spfx webpart that uploads to the attachments on a SharePoint list item. I can successfully upload, but the user should be able to click on the SP list item (it then brings up the modal showing the attached files) and then allow them to delete an attachment, then finally click an update button which adds the new file and/or removes the unwanted file. At the moment I'm using this to add files: private _addFile = (event) => { let resultFile = event.target.files; console.log(resultFile, 'resultFile'); let fileInfos = []; for (var i = 0; i < resultFile.length; i++) { var resfile = resultFile[i]; console.log(resfile, 'resfile'); var reader = new FileReader(); reader.onload = ((file) => { return (e) => { //Push the converted file into array fileInfos.push({ "name": file.name, "content": e.target.result }); this.setState({ addedFiles: [...this.state.addedFiles, ...[file.name]] },() => { if(this.state.addedFiles[0]){ this.setState({ FileAttachment1: fileInfos[0].name }); } if(this.state.addedFiles[1]){ this.setState({ FileAttachment2: fileInfos[1].name }); } if(this.state.addedFiles[2]){ this.setState({ FileAttachment3: fileInfos[2].name }); } }); }; })(resfile); reader.readAsArrayBuffer(resfile); // @ts-ignore const fileListToArr = Array.from(resultFile); if(this.state.fileArray){ this.setState({ fileArray: fileListToArr }, () => { console.log(this.state.fileArray, 'this.state.fileArray'); }); } this.setState({ fileInfos, }); } } I'm using this to retrieve files (when the user clicks the SP item): let attachmentName = sp.web.lists.getByTitle("MyList").items.getById(sid); attachmentName.attachmentFiles.get().then((files)=>{ this.setState({ fileInfos: files }); And I have a delete icon next to each file in the list which picks up the id of the deleted item, here's the JSX for one of the uploaded items: <p>{this.state.FileAttachment1 ? this.state.FileAttachment1 : null} {this.state.FileAttachment1 ? <div className={styles.editIcon}><Icon iconName="Delete" id={'att1'} onClick={this._removeFile}/></div> : null } </p> I've tried this to remove the files: private _removeFile = (ev) => { const cid = ev.target.id; console.log(cid, 'cid'); //this gives the id for the selected file. console.log(this.state.fileInfos); let filteredArray = this.state.fileInfos.filter(item => ); this.setState({ fileInfos: filteredArray, },() => {console.log(this.state.fileInfos, 'state.fileInfos');}); if(cid == 'att1'){ this.setState({ }); } if(cid == 'att2'){ this.setState({ }); } if(cid == 'att3'){ this.setState({ }); } } As you can see on that last function I've been trying to use a filter to remove the item from the array fileInfos, but whenever I click on delete to remove a file it's not removing it from the fileInfos array in state. Has anyone got a better solution or better yet, a better file management system I could use? PS. I know it's frowned upon to use file attachments on list items.3.6KViews0likes0CommentsHow would I add error handling to this sp.utility.sendEmail?
This function sends an email using the sp.utility.sendEmail from pnp.sp: public email1 = () => { const emailProps: IEmailProperties = { To: [this.props.pnltoemail1,this.props.pnltoemail2,this.props.pnltoemail3], CC: [], BCC: [], Subject: "This email is about...", Body: "Here is the body. <b>It supports html</b>", AdditionalHeaders: { "content-type": "text/html" } }; sp.utility.sendEmail(emailProps).then((result) => { console.log(result); console.log("Email Sent!"); }); } I had one instance where it didn't send the email. I need some kind of feedback to say whether it sent or not. I've read the documentation: https://pnp.github.io/pnpjs/sp/sp-utilities-utility/ As you can see I'm trying to log the result. I get an odata.null: true but I'm unsure whether that indicates a successfull send. The emails are successfully sending. Additional: Would I use an error boundary here? After researching, that seems to be overkill. If I receive a 400 return, then how would I capture that and display an error?2KViews0likes1CommentHow to use @pnp/sp to query a person column in an SP list to get the name
I have a web part that which needs to retrieve the Name property of a person column (a people picker) so I can populate state with it and subsequently populate a field. Here's the function that queries the item: private _jeChange = (ev: React.FormEvent<HTMLDivElement>, option?: IDropdownOption, index?: number) => { this.setState({ SelectedJE: option.text, }, () => { const selJE = this.state.SelectedJE; if (selJE && selJE.length > 0) { let _item = this.state.MyListItems.find((item) => { return item.JobRef == selJE; }); this.setState({ JEDeptContact: _item.DeptContactId, }, () => { sp.web.lists.getByTitle("MyList").items.getById(_item.Id).select("DeptContact", "Lookup/Name", "Lookup/ID").expand("Lookup").get().then((item: any[]) => { console.log(item); }); }); } }); } The _item.DeptContactId successfully populates the state with the Id of the user in the person column, but I want the Name not the Id, how would I resolve the Id to the Name? Do I need to use expand, if so how?3.8KViews0likes0CommentsRe: What format should the defaultSelectedUsers be for the pnp PeoplePicker?
This seems to have worked, but I need to test it thoroughly, if anyone can see any probs with it please let me know: public compilePanellists = () => { //@ts-ignore panellists.flat(); this.setState({ Panellists: panellists }, () => { console.log(this.state.Panellists); }); }1.3KViews0likes0CommentsWhat format should the defaultSelectedUsers be for the pnp PeoplePicker?
I'm struggling to populate the people picker here: <PeoplePicker context={this.props.context} personSelectionLimit={3} groupName={''} // Leave this blank in case you want to filter from all users showtooltip={false} isRequired={false} disabled={false} selectedItems={this._getPanellistsPickerItems}//This is the 'onChange' showHiddenInUI={false} defaultSelectedUsers={panellists ? panellists : []} principalTypes={[PrincipalType.User]} resolveDelay={1000} ensureUser={true} /> I'm trying to populate it with the items retrieved from an SP list. As you can see it is a multi-person PP which accepts 3. I have a component scope variable that I believe is populated correctly with all users, this logs as: (3) ["user03@domain.com", "user02@domain.com", "user01@domain.com"] 0: "user02@domain.com" 1: "user01@domain.com" 2: "user02@domain.com" length: 3 __proto__: Array(0) But if I add the panellists[] to the defaultSelectedUsers, it doesn't display anything on retrieval. I the formatting wrong? Regards, T1.3KViews0likes1CommentFormatting a column with hyperlinks (hyperlink column) using JSON
I'm trying to format a hyperlink column but am struggling with the JSON sample provided here: https://docs.microsoft.com/en-us/sharepoint/dev/declarative-customization/column-formatting We have hyperlinks in a custom list. The items are Stable, Low Risk and High Risk and we want to apply RAG colours to those. Can anyone supply some JSON? I've spent time trying to figure it but I'm struggling.4.7KViews0likes0CommentsUsing Planner in a SharePoint webpart?
My customer wants to use O365 Planner with an spfx webpart I've created. I would like to list all the tasks within Planner with a SharePoint list item surfaced on the webpart. Is this possible? If so, can someone give me a rough idea of what would be involved? Regards, CSolved815Views0likes1CommentHow to split list across several pages (SPFX/React)
I'm creating a webpart that surfaces a SharePoint list. I'm trying to split the list up into pages, but getting stuck on basic JavaScript here, mixed with some React. Here's the function that gets the list, at the top is where I am trying to work out how many pages are needed if I wanted to display 2 items per page and my attempt to slice the mapping of the new array. public _getListItems() { sp.web.lists.getByTitle("Reports").items.get().then((items: any[]) => { let returnedItemsFullA: IListAItem[] = items.map((item) => { return new ListAItem(item); }); console.log(returnedItemsFullA.length); let returnedItemsFullALength = returnedItemsFullA.length; let howManypagesA = Math.ceil(returnedItemsFullALength/2); //this works out how many pages will be needed to just show 2 items per page this.setState({ListAPages: howManypagesA}); console.log(this.state.ListAPages+'state.ListAPages'); let pageNumber = this.state.ListAPage; let returnedItemsSlice: IListAItem[] = items.slice(pageNumber, pageNumber*2).map((item) => { return new ListAItem(item); }); let returnedItems: IListAItem[] = items.map((item) => { return new ListAItem(item); }); console.log(returnedItemsSlice); this.setState({ Items: returnedItems, ListAItems: returnedItemsSlice, }); }); I'm only getting 1 item on the first page and nothing on the second! I have a function which updates a page number in state, which the above function uses to know what page number has been selected by the user. Would I need to trigger the function above, every time the next or prev page is entered?1.3KViews0likes0CommentsUsing ListItemAttachments (pnp) - I don't know how to use it!
I need to make a file upload to an SPO list for an SPFX web part form I'm making. I've put this into my JSX: <ListItemAttachments listId='23083058-4496-4367-9692-0c6fc430cce0' itemId={1} context={this.props.context} disabled={false} /> How do you use it? I understand that this may be something that lists existing attachments, so in my case, because the form hasn't submitted anything yet, the item doesn't exist to hold an item. Despite that, my form allows clicking on existing items, WITH ATTACHMENTS, but still doesn't work and gives the same error when I go to the page with the ListItemAttachments field. Is there anything that I can use for just a simple upload attachment folder that will show the existing attachment when a user opens up and existing item?Solved1.6KViews0likes1CommentDeployed web part is showing errors in console but not for non-local workbench
I have deployed a web part to a site collection (where the web part is designed to go) and I am getting errors for 3 particular features on the form. I am using sp.web for these features. I have created a 'Hello User' which uses this function: public _getUser() { sp.web.currentUser.get().then((user) => { this.setState({ CurrentUserTitle: user.Title, FullName: user.Title, CurrentUser: user.LoginName, CurrentUserID: user.Id, CurrentUserEmail: user.Email, } 2. A Departments list drop down which populates with an SP list: public _getDepartments() { sp.web.lists.getByTitle("Departments").items.get().then((items: any[]) => { let returnedDepts: IDropdownOption[] = items.map((item) => { return { key: item.Title, text: item.Title }; }); this.setState({ DepartmentsList: returnedDepts }); }); } 3. A Submit button. The function: private _onSubmit() { sp.web.lists.getByTitle('Data and Report Form').items.add({ FullName: this.state.FullName, UniId: this.state.UniId, Email: this.state.UserEmail, Phone: this.state.PhoneNo, Department: this.state.SelectedDept, SubDepartment: this.state.SubDepartment, StartDate: this.state.StartDate, DiscoveryDate: this.state.DateOfDiscovery, Details: this.state.IncidentDetails, PersonalData: this.state.PersonalData }).then((iar: ItemAddResult) => { console.log(iar); let list = sp.web.lists.getByTitle('Data and Report Form'); list.items.getById(iar.data.Id).update({ Title: 'DIBR'+iar.data.Id, }); this.setState({ JobRef: iar.data.Id, }); }); } The form works perfectly in non-local SharePoint workbench served on the actual site it's meant to be deployed on. When deployed as a package to the site itself and added as a web part it now shows these errors: HTTP404: NOT FOUND - The server has not found anything matching the requested URI (Uniform Resource Identifier). (Fetch)GET - https://myDomain.sharepoint.com/sites/IncidentReporting/SitePages/_api/web/currentuser HTTP404: NOT FOUND - The server has not found anything matching the requested URI (Uniform Resource Identifier). (Fetch)GET - https://myDomain.sharepoint.com/sites/IncidentReporting/SitePages/_api/web/lists/getByTitle('Departments')/items I get a similar message when trying to submit. A I said, these all work on the non-local workbench. Additional details: If I add the webpart to the homepage of the modern site as a web part I get these error (different to the ones if I add the webpart to a page): HTTP404: NOT FOUND - The server has not found anything matching the requested URI (Uniform Resource Identifier). (Fetch)GET - https://MyDomain.sharepoint.com/sites/_api/web/lists/getByTitle('Departments')/items HTTP404: NOT FOUND - The server has not found anything matching the requested URI (Uniform Resource Identifier). (Fetch)GET - https://MyDomain.sharepoint.com/sites/_api/web/currentuser as you can see it's missing the actual site in the URL. Why the difference? Has anyone got an idea why it's behaving differently when deployed? And why is it showing a different error if I place the web part on different areas of the site collection. T1KViews0likes0CommentsHow to set the default for a pnp.sp people picker
I want a pnp.sp people picker to auto populate with the logged in user. Here's the render and the people picker: <PeoplePicker context={this.props.context} personSelectionLimit={1} groupName={''} // Leave this blank in case you want to filter from all users showtooltip={false} isRequired={false} disabled={false} selectedItems={this._loggedInUser}//This is the 'onChange' showHiddenInUI={false} defaultSelectedUsers={this.state.LoggedInUserPPDefaultItems ? this.state.LoggedInUserPPDefaultItems : []} principalTypes={[PrincipalType.User]} resolveDelay={1000} ensureUser={true} /> The defaultSelectedUsers doesn't seem to work the way it's described. It requires a string array but if I put a state object of the logged in users email or login name (a string array type) into it nothing happens, the people picker stays blank. I have a getUser() function setting the state here: public _getUser() { //getUser sets the state for multiple properties of the user. sp.web.currentUser.get().then((user) => { this.setState({ CurrentUserTitle: user.Title, CurrentUser: user.LoginName, CurrentUserID: user.Id, CurrentUserEmail: user.Email } } } Here's the function on change: This allows the people picker to be changed, if items is blank etc. Otherwise it populates the state. I'm not sure which state to use for the people picker. private _loggedInUser(items) { if(items !== null && items.length > 0){ this.setState({ LoggedInUser: items[0].id, LoggedInUserPPDefaultItems: [items[0].secondaryText] }); } } My states involved: Set in constructor: LoggedInUserPPDefaultItems: [], LoggedInUser: null, CurrentUserTitle: null, CurrentUser: null, CurrentUserGroups: null, CurrentUserID: null, CurrentUserEmail: null, In state file (separate interface): LoggedInUserPPDefaultItems: string[]; LoggedInUser: string; CurrentUserTitle: string; CurrentUser: string[]; CurrentUserGroups: string; CurrentUserID: string; CurrentUserEmail: string; any ideas?13KViews0likes8Comments
Groups
Recent Blog Articles
No content to show