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?
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!
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
});
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
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
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':
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'
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:
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
Fingers crossed that's right, and then if it is we need to update the documentation!
regards
Marc
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:
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
I 100% subscribe to the "learning by breaking stuff" approach :-D
PR created.
thanks, Jesper!
I can't see the PR though? can you send me a link - and I'll approve it...
regards
marc
Guess I missed creating the actual PR.
Here you go: https://github.com/umbraco/UmbracoDocs/pull/4336
Best wishes Jesper
is working on a reply...