Chart Web Part – SharePoint 2013

In SharePoint 2010, there was a Chart Web Part that you could connect to another web part on the same page, to a list anywhere in the site collection, to an external content type, or to data from an Excel workbook.

In SharePoint 2013, this does not exist OOB.

However, if you copy and paste this code and save it as an XML file, you can upload it and use it in 2013!


<?xml version="1.0" encoding="utf-8"?>
<webParts>
<webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
<metaData>
<type name="Microsoft.Office.Server.WebControls.ChartWebPart,microsoft.office.server.chart,Version=14.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" />
<importErrorMessage>Cannot import Chart Web Part.</importErrorMessage>
</metaData>
<data>
<properties>
<property name="Title" type="string">Chart Web Part</property>
<property name="Description" type="string">Helps you to visualize your data on SharePoint sites and portals.</property>
</properties>
</data>
</webPart>
</webParts>

Navigate to the page you where you want to add a chart and go into edit mode.

Click the insert tab and select Web Part.

Click “Upload a Web Part” and browse to the XML file you saved from the code above.

Click Upload.

chart

The page will refresh so you’ll have to go back into the Web Part menu to select the Chart Web Part from the Imported Web Parts category.

chartwebpart.PNG

Click Add and voila!

chartwebpart1.PNG

Save the page before you click on the Data & Appearance or Advance Properties links.

Working Around Low Disk Space During A Full Crawl

TIL that space is released when you pause a crawl!

Backstory:

We decided to re-index our SharePoint site due to spotty search results, and learned the hard way that we didn’t have enough space to run a full crawl.

Adding space wasn’t an option and I had to get the search working again or else face the wrath of the users who rely on it. I decided I’d run the full crawl and pause it before free space got too low. That way some things would be searchable at least.

To my surprise, a ton of drive space freed up when I paused the crawl, and items that had already been crawled were still searchable! Using that to my advantage, I spent the rest of the day pausing and resuming the full crawl until it was finished. Tedious, but worth it.

Summary:

If you don’t have enough disk space to run a full crawl straight through, monitor the drive while the crawl is running and pause it when you need to free up space. Once the crawl’s status changes from “Pausing” to “Paused”, confirm that space is available again and resume crawling. Repeat as necessary.

Thoughts:

Releasing space seems like basic functionality. Does the crawler really not have the ability to determine free space on the drive where temp files are stored? Why doesn’t it pause itself when the “low disk space” event is triggered? Why are temp files stored on the system drive by default if there isn’t a mechanism that prevents the drive from bottoming out, corrupting the index? Am I missing something?

That being said, I’m not convinced of the health of our search service application.

Recent Crawl/Query Rates Incorrectly Show 0.00 Items Per Second

Problem:

“Recent crawl rate” and “Recent query rate” statistics incorrectly show 0.00 items per second on the Search Administration page.

zero1

Confirmed the crawl rate from the Crawl Health Reports page.

crawlgraph

Confirmed that the number of searchable items was increasing.

Found a TON of update conflict errors (event ID 6398 and 6482) in the Application event logs.

errors

Solution:

Clear the configuration cache:

  1. Stop the Windows SharePoint Services Timer service.
  2. Navigate to the cache folder %SYSTEMDRIVE%\ProgramData\Microsoft\SharePoint\Config
  3. Locate the folder that has the “Cache.ini” file. The folder name should be a GUID.
    explorer
  4. Back up the Cache.ini file (copy and paste it into parent folder, append .bak to the filename).
  5. Delete all the XML configuration files in the GUID folder. NOTE: DO NOT DELETE the Cache.ini or the GUID folder!
  6. Edit the Cache.ini file.
  7. Replace the number in the file with a “1”. Save.
    cache
  8. Start the Windows SharePoint Services Timer service.
  9. After the XML files repopulate, confirm that the Cache.ini file in the GUID folder contains the original number.

Confirm that “Recent crawl rate” and “Recent query rate” show data.

zero

Link To New Item Form

Give users the ability to add items to a list without showing the entire list web part. In my example, I’ve added a “Submit Request” button to a Document Set Welcome Page. Clicking this will open the New Item form for my Tickets list.

docset


<script type="text/javascript">

 function displayLayover(url) {

 var options = SP.UI.$create_DialogOptions();

 options.url = url;

 options.dialogReturnValueCallback = Function.createDelegate(

 null, null);

 SP.UI.ModalDialog.showModalDialog(options);

 }

 </script>

<input type="button" onclick='javascript:displayLayover("/sites/sandbox/mustard/Lists/Tickets/NewForm.aspx")' value="Submit Request">

Steps:

1. Add a Script Editor web part to your page.

2. Click EDIT SNIPPET.

3. Replace the URL in this line with the path to your list’s New Item form (you can also change what the button says by changing the ‘value’):

<input type="button" onclick='javascript:displayLayover("/sites/sandbox/mustard/Lists/Tickets/NewForm.aspx")' value="Submit Request">

NOTE: If your URL looks something like this: /sites/sandbox/mustard/_layouts/15/start.aspx#/Lists/Tickets/NewForm.aspx, remove /_layouts/15/start.aspx# from the path.

embed

4. Click Insert and save the page.

5. To test, click the new “Submit Request” button.

formpopup1

6. Add some information and click Save.

7. Navigate to the list to confirm.

ticket

Edit Form Popup – Drag And Drop

By default, the edit form does not pop up when you drag and drop documents into a library. This piece of JavaScript will force an edit form to pop up for as many documents you drag and drop. For example, if you drag 5 documents at the same time, 5 individual edit forms will pop up in succession.

1. Make sure that the Metadata Navigation and Filtering site feature is enabled.

2. Navigate to and edit the page you are adding this to.

3. Insert a Script Editor web part and embed the following code (no changes need to be made, just copy/paste):


<script unselectable="on">

(function (_window) {

    var maxTimeForReplaceUploadProgressFunc = 10000;

    function replaceUploadProgressFunc() {

        if (typeof _window.UploadProgressFunc != 'undefined') {

            _window.Base_UploadProgressFunc = _window.UploadProgressFunc;

            _window.UploadProgressFunc = Custom_UploadProgressFunc;

            console.log('replaced dialog');

        } else if (maxTimeForReplaceUploadProgressFunc > 0) {

            maxTimeForReplaceUploadProgressFunc -= 100;

            setTimeout(replaceUploadProgressFunc, 100);

        }

    }

    setTimeout(replaceUploadProgressFunc, 100);


    function Custom_UploadProgressFunc(percentDone, timeElapsed, state) {

        _window.Base_UploadProgressFunc(percentDone, timeElapsed, state);

        var messageType = ProgressMessage.EMPTY;

        switch (state.status) {

            case 1:

                messageType = ProgressMessage.VALIDATION;

                break;

            case 3:

                messageType = ProgressMessage.UPLOADING;

                break;

            case 4:

                messageType = ProgressMessage.UPLOADED;

                OpenEditFormForLastItem(state);

                break;

            case 5:

                messageType = ProgressMessage.CANCELLED;

                break;

        }



        function OpenEditFormForLastItem(state) {

            var caml = '';

            caml += "<View>";

            caml += "<Query>";

            caml += "<Where>";



            if (state.files.length > 1) {

                caml += "<In>";

                caml += "<FieldRef Name='FileLeafRef'/>";

                caml += "<Values>";

            } else {

                caml += "<Eq>";

                caml += "<FieldRef Name='FileLeafRef'/>";

            }



            state.files.forEach(function (file) {

                //only succesfull uploaded files that arent overwrites

                console.log(file);

                if (file.status === 5 /*&& !file.overwrite*/) {

                    caml += "<Value Type='File'>" + file.fileName + "</Value>";

                }

            }, this);


            if (state.files.length > 1) {

                caml += "</Values>";

                caml += "</In>";

            } else {

                caml += "</Eq>";

            }


            caml += "</Where>";

            caml += "<OrderBy><FieldRef Name='ID' Ascending='True' /></OrderBy>";

            caml += "</Query>";

            caml += "<ViewFields><FieldRef Name='ID' /></ViewFields>";

            caml += "<RowLimit>500</RowLimit>";

            caml += "</View>";

            console.log(caml);



            var cntxt = SP.ClientContext.get_current();

            var web = cntxt.get_web();

            var list = web.get_lists().getByTitle(window.ctx.ListTitle);

            var query = new SP.CamlQuery();

            query.set_viewXml(caml);

            var items = list.getItems(query);

            cntxt.load(list, 'DefaultEditFormUrl');

            cntxt.load(items);

            cntxt.executeQueryAsync(function () {

                var listEnumerator = items.getEnumerator();

                function openEditForItem() {

                    if (listEnumerator.moveNext()) {

                        var item = listEnumerator.get_current();

                        var id = item.get_id();



                        var options = SP.UI.$create_DialogOptions();

                        options.title = "Add File Metadata";

                        options.url = list.get_defaultEditFormUrl() + '?ID=' + id;

                        options.autoSize = true;

                        options.dialogReturnValueCallback = openEditForItem;

                        SP.UI.ModalDialog.showModalDialog(options);

                    } else {

                        location.reload();

                    }

                }

                openEditForItem();

            }, function (error, args) {

                    console.log("failed to get new uploaded items");

                    console.log(error);

                    console.log(args);

                });

        }

    }

})(window);

</script>

4. Click OK and save the page.

5. Confirm that the edit form pops up when you drag and drop documents.

Mass Delete Empty Folders With PowerShell

If you don’t feel like manually deleting empty folders, use this PowerShell script to query and delete all empty folders and subfolders. Make sure you change the $WebURL to your SharePoint site or subsite, and the $listName to your library.


Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue

function EmptyFolders()
{
$WebURL = "http://sp2013/sites/company"
$webDestination = Get-SPWeb -identity $WebURL
$listName = "Documents"

$query = New-Object Microsoft.SharePoint.SPQuery;
$query.ViewAttributes = "Scope='RecursiveAll'";
$query.RowLimit = 5000
$caml = "<Where>
<Eq>
<FieldRef Name='ContentType' />
<Value Type='Text'>Folder</Value>
</Eq>
</Where>"

$query.Query = $caml

$list = $webDestination.Lists[$listName]
$folder = $list.GetItems($query)
do
{
$query.ListItemCollectionPosition = $folder.ListItemCollectionPosition
for ($index = $folder.Count - 1; $index -gt -1; $index--)
{
if ($folder[$index]["FolderChildCount"].Replace(';#', '') -eq 0 -and $folder[$index]["ItemChildCount"].Replace(';#', '') -eq 0)
{
Write-Host("$($folder[$index]["FolderChildCount"].Replace(';#', '')), $($folder[$index]["ItemChildCount"].Replace(';#', '')), $($folder[$index]["ContentType"]), $($folder[$index].URL)")
$folder[$index].Delete();
$list.Update()
}
}
}
While($query.ListItemCollectionPosition -ne $null)
#$list.Update();
$webDestination.Dispose()
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("Operation Completed",0,"Done",0x1)
}
EmptyFolders

Library Paging – First Page Button

Adding a “First Page” button is a simple work around for getting back to the first page when paging through documents. This is especially handy if you use document sets.

  1. Edit the page and add a Script Editor web part.
  2. Click EDIT SNIPPET.embed
  3. Embed the following code:

<!DOCTYPE html>
<html>
<body>

<input type="button" value="First Page" onclick="location.href=''"/>

</body>
</html>

I moved the Script Editor web part down below the library web part and changed the Direction to Right to Left.

scripteditor

Final product:

docsetbutton.PNG

Next page:

docsetbutton1.PNG