• Get count of items/files in list/document library in SharePoint Online with SPFx

    In SharePoint Online, when we view Site Contents, internally a call is made to the end point /_api/web/AppTiles to get the count of items/files in list/document library that the current site collection has. We can call this API in SPFx webpart to get these details. Below is the sample code.

    import { SPHttpClient, SPHttpClientResponse, SPHttpClientConfiguration } from '@microsoft/sp-http';
    
    this.context.spHttpClient.get(`${this.context.pageContext.web.absoluteUrl}/_api/web/AppTiles`, SPHttpClient.configurations.v1)
      .then((response: SPHttpClientResponse) => {
        response.json()
          .then((responseJSON: any) => {
            console.log(responseJSON); // Gets all the list and document library details in JSON
          })
          .catch(error => {
            console.log(error);
          });
      })
      .catch(error => {
        console.log(error);
      });

    this.context refers to WebPartContext in the BaseClientSideWebPart class. The output will looks something like below JSON snippet. There is a lot of detail here which we can filter using $select. The attributes we require are Title and ChildCount.

    {
        "@odata.context": "https://mysite.sharepoint.com/sites/mysitecollection/_api/$metadata#AppTiles",
        "value": [
          {
            "@odata.type": "#SP.AppTile",
            "@odata.id": "https://mysite.sharepoint.com/sites/mysitecollection/_api/SP.AppTile0aab34a5-8bb4-4d5e-bac0-90841a08dd34",
            "@odata.editLink": "SP.AppTile0aab34a5-8bb4-4d5e-bac0-90841a08dd34",
            "AppId": "58de69fc-9e3f-4375-af44-205eeb452366",
            "AppPrincipalId": "",
            "AppSource": 0,
            "AppStatus": 4,
            "AppType": 0,
            "AssetId": "0;00bfea23-e717-4e80-bb17-d0c71b360101;101;",
            "BaseTemplate": 101,
            "ChildCount": 5,
            "ContentMarket": "",
            "CustomSettingsUrl": "",
            "Description": "",
            "IsCorporateCatalogSite": false,
            "LastModified": "4/26/2020 4:16 AM",
            "LastModifiedDate": "2020-04-26T11:16:27Z",
            "ProductId": "00cfea20-e900-4e80-aa17-d0c71b360101",
            "Target": "/sites/mysitecollection/Shared Documents/Forms/AllItems.aspx",
            "Thumbnail": "/_layouts/15/images/ltdl.png?rev=47",
            "Title": "Documents",
            "Version": "4"
          },
          ...
        ]
      }

  • Adding boilerplate code of React component in SPFx using VS Code

    React does not provide command line interface like Angular’s ng generate to create boilerplate code for React components. So you end up copying code from previous components and then modifying it. VS Code has snippets feature that we can leverage to create our own boilerplate code.

    To create your own snippets, go to User Snippets under File > Preferences (Code > Preferences on macOS) and select New Global Snippets file… Enter the name of the snippet file. You get a JSON file with below contents.

    {
    	// Place your global snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and 
    	// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope 
    	// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is 
    	// used to trigger the snippet and the body will be expanded and inserted. Possible variables are: 
    	// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. 
    	// Placeholders with the same ids are connected.
    	// Example:
    	// "Print to console": {
    	// 	"scope": "javascript,typescript",
    	// 	"prefix": "log",
    	// 	"body": [
    	// 		"console.log('$1');",
    	// 		"$2"
    	// 	],
    	// 	"description": "Log output to console"
    	// }
    }

    Update the file with below code.

    {
    	"SPFx React Component Template": {
    		"prefix": "spfxtsx",
    		"body": [
    			"import * as React from 'react';" ,
    			"export default class $1 extends React.Component<I$1Props, {}> {" ,
    			"    constructor(props: I$1Props, public state: any) {" ,
    			"        super(props);" ,
    			"    }" ,
    			"    public componentDidMount() {" ,
    			"    }" ,
    			"    public render(): React.ReactElement<I$1Props> {" ,
    			"        return(<>" ,
    			"        </>);" ,
    			"    }" ,
    			"}" ,
    			"interface I$1Props {}"
    		],
    		"description": "Creates React component boilerplate code for SPFx"
    	}
    }

    The prefix (spfxtsx) here is the trigger text which will give you option to enter the snippet. $1 indicates tabstop and allows user to enter the name of the component, which is also used in name of props interface. In your tsx file when you start entering spfxtsx, it will populate with boilerplate code.

  • Uploading file with progress indicator in SPFx webpart using PnPJS in SharePoint

    SharePoint provides StartUpload, ContinueUpload and FinishUpload REST APIs to upload large files in chunk. PnPJS Library simplifies the implementation and we have to call only one method to upload file in chunks.

    To upload file in chunks in PnPJS, you call addChunked method by supplying a callback function which can be used to track the progress of the upload.

    sp.web.getFolderByServerRelativeUrl("/sites/naveegator/Shared%20Documents/")
        .files
        .addChunked(file.name, file,
            data => {
                // Here we update the progress by fetching data.blockNumber and data.totalBlocks
            }, true)
        }

    The third parameter in addChunked method is the callback function which provides ability to view in how many chunks the file are being uploaded (totalBlocks) and what is the current chunk (blockNumber) that is being uploaded. Using this information we can create progress bar to show percentage of file uploaded. Below is the React component in SPFx webpart. It uses PorgressIndicator from Office UI Fabric aka Fluent UI to display the progress bar.

    import * as React from 'react';
    import { ProgressIndicator } from 'office-ui-fabric-react/lib/ProgressIndicator';
    import { PrimaryButton } from 'office-ui-fabric-react';
    import { sp } from "@pnp/sp/presets/all";
    
    export default class UploadFile extends React.Component<IUploadFileProps, {}> {
      constructor(props: IUploadFileProps, public state: any) {
        super(props);
    
        this.state = {
          showProgress: false,
          progressLabel: "File upload progress",
          progressDescription: "",
          progressPercent: 0
        };
      }
    
      public render(): React.ReactElement<IUploadFileProps> {
        return (
          <>
            <input type="file" id="fileInput" /><br />
            <PrimaryButton text="Upload" onClick={this.uploadFile} /> <br />
            <ProgressIndicator
              label={this.state.progressLabel}
              description={this.state.progressDescription}
              percentComplete={this.state.progressPercent}
              barHeight={5} />
          </>
        );
      }
    
      private uploadFile = () => {
        let input = document.getElementById("fileInput") as HTMLInputElement;
        let file = input.files[0];
        let chunkSize = 40960; // Default chunksize is 10485760. This number was chosen to demonstrate file upload progress
        this.setState({ showProgress: true });
        sp.web.getFolderByServerRelativeUrl("/sites/naveegator/Shared%20Documents/")
          .files
          .addChunked(file.name, file,
            data => {
              let percent = (data.blockNumber / data.totalBlocks);
              this.setState({
                progressPercent: percent,
                progressDescription: `${Math.round(percent * 100)} %`
              });
            }, true,
            chunkSize)
          .then(r => {
            console.log("File uploaded successfully");
            this.setState({
              progressPercent: 1,
              progressDescription: `File upload complete`
            });
          })
          .catch(e => {
            console.log("Error while uploading file");
            console.log(e);
          });
    
      }
    }
    
    interface IUploadFileProps { }
    

    I have used chunkSize as 40960 so that I could display the progress bar for smaller sized file. For actual implementation you can omit that argument.

  • The Stockdale Paradox

    You must never ever ever confuse, on the one hand, the need for absolute, unwavering faith that you can prevail despite those constraints with, on the other hand, the need for the discipline to begin by confronting the brutal facts, whatever they are.

    The Stockdale Paradox

  • Passing function keys to Windows on Amazon WorkSpaces from MacBook with Touch Bar

    If you have MacBook with Touch Bar and you use it to access Windows on Amazon WorkSpaces then pressing fn + (function key) does not do anything on Windows. To get around this problem you have to update the below settings.

    Go to  > System Preferences… > Keyboard and update the settings Touch bar shows to F1, F2, etc. Keys.

    Downsides to this work around:

    • The function key F11 still goes to Mac and shows Desktop on Mac
    • You lose direct access to App Controls via Touch Bar
  • The Ellsberg Paradox

    You’re in a room with two large urns.

    The urns are covered so you can’t see inside them. But you know the urn on the left contains 50 white marbles and 50 black marbles. The urn on the right also contains 100 marbles, but the ratio of white to black marbles is unknown, with every ratio as likely as any other.

    […]

    What Ellsberg found is that people overwhelmingly choose to draw the ball from the urn with a known set of probabilities, rather than take a chance on the urn with an unknown ratio.

    This is despite the fact that the second urn could have better odds of drawing black marbles, like 99 to 1 or even 100 to no white marbles. Of course, the ratio in the unknown urn could also be tilted in the other direction. There’s no way of knowing.

    The fact is, the probability of drawing a black marble from either urn is identical.

    To verify this for yourself, just simplify the example.

    Instead of 100 marbles, imagine there are only 2. In the known urn, there is 1 black and 1 white. In the unknown urn, one-third of the time you’d be picking out of an urn with 2 black marbles. Another third of the time, 2 white marbles. And another third of the time, the urn has 1 of each.

    When you sum these probabilities up, you see that the chance of picking a black marble in the second urn is identical to picking one from the first urn: 50%.

    […]

    The takeaway? People exhibit strong aversion to ambiguity and uncertainty, meaning they have an inherent preference for the known over the unknown.

    The Ellsberg Paradox: Why You Don’t Take Risks and Settle for the Mediocre

    Thanks to Finshots for dropping this one in my inbox.

  • View all print screen keyboard shortcuts on Mac

    > System Preferences… > Keyboard > Shortcuts > Screenshots

  • Chotta cha chann

    The title would be incomprehensible as of now but read on to find out its meaning.

    A few days back me and my wife were travelling from Mangalore to Mumbai. Between our journey another family boarded the train at Goa. Father, mother and two cute daughters — probably 7 and 2 years old. The younger one was the pretty active, trying to analyze just about everything around her and speaking in her incomprehensible language.

    We started talking to the family, the usual stuff — what brings you here, where are you headed and so on. And then the younger one started saying “Chotta cha chann” — continuously. I turned to my wife and asked “Kya bol rahi hai yeh?” (What is she saying).

    My wife then replied back, holding (supposedly mineral from Indian Railways) water bottle we had bought earlier. She pointed to a small picture of rising sun (in red color) drawn on the water bottle. The kid was referring to that sun and was saying — “Chota saa sun” (A small sun).

    I was dumbstruck. And amused. Of all the things in the compartment — seats, window, suitcases, the water bottle itself — she chose to identify that tiny little sun drawn on the water bottle.

    The mother then narrated us a story of a time when the elder daughter was of the age of younger one. They had accumulated a bunch of tomato ketchup sachets from their orders in McDonald’s. One day the elder daughter got hold of all the sachets and sorted them in two categories — regular and chilly. How? Based on the picture of red chilly drawn on on the sachets.

    This is something that would be helpful to me after after some years!

  • My (unsolicited) advice to management of Adlabs Aquamagica

    I recently went to Adlabs Aquamagica water park near Mumbai. If you haven’t heard about it, then a simple Google search would help you out.

    As it’s a water park and I didn’t have a water proof mobile or camera I decided to leave them behind. After finishing just about every water ride there was a photographer from Aquamagica (with a water proof camera) ready to take our photos. These photos somehow manage to capture the excitement and thrill of the ride on your face, which starts to fade away after a few seconds with the onset of realization that you have to climb those 100 steps to get into the water ride again.

    So, at the end of the day I decided to have a look at my photographs. They looked pretty good and as I said – captured the excitement and thrill on our faces. So I asked the guy at the counter how much I need to pay for them. He replied back with all the details, but my ears went deaf the moment I heard printed copy.

    I took out my smartphone just to check the current year and confirm if any rides were so fast that it turned time back for me sending me in past when Kodak ruled the world. No it was still 2014. I checked with him again. Same reply. I asked if I can get these copies emailed or on a CD. Negative reply. I checked his camera to see if it was a digital camera. Yes it was. I was dumbfounded. This brand new theme park has RFID band to open lockers assigned to its guests and supports cashless payment using bar code on wristband[1] but it cannot email me my photographs!

    So here’s my advice to management of Adlabs Aquamagica – let your guests receive a digital copy of photographs. Why? Well here are some of my reasons –

    1. Guests can carry their own camera in a theme park. But for a water park guests would need a special camera which not everyone has. So there is a real opportunity here for business to sell digital copies of photographs. And I am pretty sure more people would be willing to pay for it. More than people willing to pay for hard copy.

    2. In the age of Facebook, Instagram and WhatsApp hard copies of photographs of are pretty much worthless. They would end up in a wall on your home visible only to you. Post them on social media and it gets an audience.

    3. One side effect, and a good side effect, of posting photographs on social media is free advertisement. Rather than buying ads on Facebook costing 100s of dollars why not let guests buy digital photographs for 100s of rupees allowing them to post to Facebook and letting their friends like and comment them. And I am pretty sure Facebook won’t be the only social media where these photographs would be posted.

    4. It seems very ridiculous when I can’t get digital copy of photographs especially after using cashless payment with bar code on wristband.

    ––––––––––

    [1] Cashless payment using bar code on wristband: Before you enter the park every guest’s wrist is strapped with a band with bar code on it. As taking your wallet inside a water park may not be a good idea, you can put money in the band to spend it inside the water park. Any unspent money is then refunded back to you when you leave the park.

  • A vicious cycle…

    *Submit*

    Your password must be at least 8 characters long.

    *Submit*

    Your password should contain at least one uppercase alphabet.

    *Submit*

    Your password should contain at least one numeric character.

    *Submit*

    Your password should contain at least one special character.

    *Submit*

    Your password cannot contain following special characters @ . / %

    *Submit*

    Your password must not be longer than 12 characters.

    Curses the website, its owner and the software engineer who created it before finally getting through.

    One month later…

    Clicks on Forgot Password?

    *Submit*

    Your password must be at least 8 characters long…

    And the vicious cycle starts all over again!