Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Jesper Skjønnemand 65 posts 440 karma points c-trib
    Sep 03, 2022 @ 16:35
    Jesper Skjønnemand
    0

    How to make nodes appear only once in custom dashboard's user activity log

    I have managed to create a friendly welcome screen for my editors by following and to some extend understanding the instructions on this brilliant tutorial https://our.umbraco.com/documentation/tutorials/Creating-a-Custom-Dashboard/

    The dashboard includes the suggested activity log which is a nice feature.

    However, if editors save or publish a page several times, it will appear on the "pick up where you left off" list several times. Ideally, a node would only appear on the list once, regardless of multiple saves or publishes.

    Can someone help me get on the right track for this?

    Best wishes Jesper

  • Marc Goodson 2141 posts 14324 karma points MVP 8x c-trib
    Sep 04, 2022 @ 09:21
    Marc Goodson
    0

    Hi Jesper,

    There does appear to be some implementation in the tutorial to try to prevent this happening...

    ... but I think I'm either reading it wrong, or it's slightly in the wrong place...

    But hopefully you can try and confirm...

    Basically we see a check to see if 'we've already grabbed this from the entityservice':

      if (nodesWeKnowAbout.indexOf(item.nodeId) !== -1)
    

    So that we only add to our filteredLogEntries list if this is an item we don't previously know about...

    and if we add one, then we add it's node id to the list of 'nodesWeKnowAbout'

    nodesWeKnowAbout.push(ent.id);
    

    but here's the thing... I think for that concept to work, the nodesWeKnowAbout variable needs to remember previous nodes that we have know about, from the previous item that is being looped through..

    ... but inside our angular.forEach(response.items loop we 'reset' the value of nodesWeKnowAbout to be an empty array:

    var nodesWeKnowAbout = [];
    

    so each time the loop fires it's forgotten what any previous nodes it used to know about!

    So unless I've monumentally misunderstood what nodesWeKnowAbout is meant to be doing (and it's highly possible that I have :-P) then it would be interesting to see if we moved that line outside of the loop would it all just work as expected, eg no duplicate nodes...

    so we would have

    logResource.getPagedUserLog(userLogOptions)
        .then(function (response) {
            console.log(response);
            vm.UserLogHistory = response;
            var filteredLogEntries = [];
            // Define supported entity types
            var supportedEntityTypes = ["Document", "Media", "MemberType", "MemberGroup", "MediaType", "DocumentType", "Member", "DataType"];
            // Loop through the response, and flter out save log entries we are not interested in
            var nodesWeKnowAbout = [];
            angular.forEach(response.items, function (item) {
                // if the query finds a log entry for an entity type that isn't supported, nothing should done with that
                if (!supportedEntityTypes.includes(item.entityType)) 
                    {
                        return;
                    }
                // if no entity exists -1 is returned for the nodeId (eg saving a macro would create a log entry without a nodeid)
                if (item.nodeId > 0) {
                    // check if we already grabbed this from the entityservice
    
                    if (nodesWeKnowAbout.indexOf(item.nodeId) !== -1)
                        return;
                    // find things the user saved and/or published
                    if (item.logType === "Save" || item.logType === "SaveVariant" || item.logType === "Publish") {
                        // check if it is media or content
                        if (item.entityType === "Document") {
                            item.editUrl = "content/content/edit/" + item.nodeId;
                        }
                        if (item.entityType === "Media") {
                            item.editUrl = "media/media/edit/" + item.nodeId;
                        }
    
                        if (typeof item.entityType !== 'undefined') {
                            // use entityResource to retrieve details of the content/media item
                            var ent = entityResource.getById(item.nodeId, item.entityType).then(function (ent) {
                                console.log(ent);
                                item.Content = ent;
                            });
    
                            nodesWeKnowAbout.push(ent.id);
                            filteredLogEntries.push(item);
                        }
                    }
                }
            });
            vm.UserLogHistory.items = filteredLogEntries;
        });
    });
    

    Fingers crossed that's right, and then if it is we need to update the documentation!

    regards

    Marc

  • Jesper Skjønnemand 65 posts 440 karma points c-trib
    Sep 04, 2022 @ 12:37
    Jesper Skjønnemand
    100

    Hi Marc

    Thanks for the suggestion. Moving the "create empty array" outside the loop makes a lot of sense to me. It did not fix the issue though, but it did not break anything either.

    Inspired by your input I decided to try a "rewrite" of the loop to achive a less convoluted structure using a "if this applies to the entry, then skip to the next entry" approach. I am very, very new to angular and JS so this is probably not best practice, but I turned out to work :-)

    My controller now looks like this:

    angular.module("umbraco").controller("DRC-dashController", function ($scope, userService, logResource, entityResource) {
        var vm = this;
        vm.UserName = "guest";
        var user = userService.getCurrentUser().then(function (user) {
            console.log(user);
            vm.UserLogHistory = [];
            vm.UserName = user.name;
        });
    
        var userLogOptions = {
            pageSize: 10,
            pageNumber: 1,
            orderDirection: "Descending",
            sinceDate: new Date(2020, 0, 1)
        };
    
        logResource.getPagedUserLog(userLogOptions)
            .then(function (response) {
                console.log(response);
                vm.UserLogHistory = response;
    
                // define the entity types that we care about, in this case only content and media
                var supportedEntityTypes = ["Document", "Media"];
    
                // define an empty array "nodes we know about"
                var nodesWeKnowAbout = [];
    
                // definde an empty array "filtered log entries"
                var filteredLogEntries = [];
    
                // loop through the entries in the User Log History
                angular.forEach(response.items, function (item) {
    
                  // if the item is already in our "nodes we know about" array, skip to the next log entry
                  if (nodesWeKnowAbout.includes(item.nodeId)) {
                    return;
                  }
    
                  // if the log entry is not for an entity type that we care about, skip to the next log entry
                  if (!supportedEntityTypes.includes(item.entityType)) {
                    return;
                  }
    
                  // if the user did not save or publish, skip to the next log entry
                  if (item.logType !== "Save" && item.logType !== "Publish") {
                    return;
                  }
    
                  // if the item does not have a valid nodeId, skip to the next log entry
                  if (item.nodeId < 0) {
                    return;
                  }
    
                  // now, push the item's nodeId to our "nodes we know about" array
                  nodesWeKnowAbout.push(item.nodeId);
    
                  // use entityResource to retrieve details of the content/media item
                  var ent = entityResource.getById(item.nodeId, item.entityType).then(function (ent) {
                      console.log(ent);
                      item.Content = ent;
                  });
    
                  // get the edit url
                  if (item.entityType === "Document") {
                      item.editUrl = "content/content/edit/" + item.nodeId;
                  }
                  if (item.entityType === "Media") {
                      item.editUrl = "media/media/edit/" + item.nodeId;
                  }
    
                  // push the item to our "filtered log entries" array
                  filteredLogEntries.push(item);
    
                // end of loop
                });
    
                // populate the view with our "filtered log entries" array
                vm.UserLogHistory.items = filteredLogEntries;
    
            // end of function
            });
    
        // end of controller
        });
    
  • Marc Goodson 2141 posts 14324 karma points MVP 8x c-trib
    Sep 04, 2022 @ 14:47
    Marc Goodson
    0

    Hi Jesper

    I think nobody really knows angularJS :-P

    but also all you need to know to make things like this work is usually workableoutable...

    (so difficult to look at something and say why it's not working, but if you can play with it and put console.log in every now and then you can usually sort something out)

    Anyway that's great that you got it working!

    Your approach is much clearer as to why an entry is being skipped, so presumably there is an issue with the existing tutorial, where some part of the logic is not being correctly checked... (or it is related somehow to the array being inside the loop)

    Would you be interested in making a PR into the official docs with your updated example?

    If you visit the link below, you can paste your example in, and create a PR

    https://github.com/umbraco/UmbracoDocs/edit/main/Tutorials/Creating-a-Custom-Dashboard/index.md

    Then it can be reviewed and updated for other future dashboard adventurers who may hit the same quirk...

    (Also you'll get the prestige [C-Trib] contributor badge added to your Our Umbraco profile!

    regards

    Marc

  • Jesper Skjønnemand 65 posts 440 karma points c-trib
    Sep 04, 2022 @ 16:10
    Jesper Skjønnemand
    0

    I 100% subscribe to the "learning by breaking stuff" approach :-D

    PR created.

  • Marc Goodson 2141 posts 14324 karma points MVP 8x c-trib
    Sep 05, 2022 @ 07:47
    Marc Goodson
    0

    thanks, Jesper!

    I can't see the PR though? can you send me a link - and I'll approve it...

    regards

    marc

  • Jesper Skjønnemand 65 posts 440 karma points c-trib
    Sep 07, 2022 @ 09:05
    Jesper Skjønnemand
    0

    Guess I missed creating the actual PR.

    Here you go: https://github.com/umbraco/UmbracoDocs/pull/4336

    Best wishes Jesper

Please Sign in or register to post replies

Write your reply to:

Draft