Skip to content

Commit

Permalink
Fix report tab sync
Browse files Browse the repository at this point in the history
Publish tno-core:0.1.149
  • Loading branch information
Fosol committed Sep 26, 2024
1 parent 7a37fbc commit 9eca00c
Show file tree
Hide file tree
Showing 46 changed files with 117 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,10 @@ public async Task<IActionResult> UpdateAsync(ReportInstanceModel model, bool upd
if (ownerId.HasValue)
{
var user = _userService.FindById(ownerId.Value) ?? throw new NotAuthorizedException();
await _kafkaMessenger.SendMessageAsync(_kafkaHubOptions.HubTopic, new KafkaHubMessage(HubEvent.SendUser, user.Username, new KafkaInvocationMessage(MessageTarget.ReportStatus, new[] { new ReportMessageModel(result) })));
await _kafkaMessenger.SendMessageAsync(
_kafkaHubOptions.HubTopic,
new KafkaHubMessage(HubEvent.SendUser, user.Username, new KafkaInvocationMessage(MessageTarget.ReportStatus, new[] { new ReportMessageModel(result) }))
);
}

return new JsonResult(new ReportInstanceModel(result, _serializerOptions));
Expand Down
35 changes: 27 additions & 8 deletions api/net/Areas/Subscriber/Controllers/ReportController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class ReportController : ControllerBase
private readonly IKafkaMessenger _kafkaProducer;
private readonly KafkaOptions _kafkaOptions;
private readonly KafkaHubConfig _kafkaHubOptions;
private readonly IKafkaMessenger _kafkaMessenger;
private readonly IImpersonationHelper _impersonate;
private readonly JsonSerializerOptions _serializerOptions;
private readonly ILogger<ReportController> _logger;
Expand All @@ -66,6 +67,7 @@ public class ReportController : ControllerBase
/// <param name="kafkaProducer"></param>
/// <param name="kafkaOptions"></param>
/// <param name="kafkaHubOptions"></param>
/// <param name="kafkaMessenger"></param>
/// <param name="impersonateHelper"></param>
/// <param name="serializerOptions"></param>
/// <param name="logger"></param>
Expand All @@ -81,6 +83,7 @@ public ReportController(
IKafkaMessenger kafkaProducer,
IOptions<KafkaOptions> kafkaOptions,
IOptions<KafkaHubConfig> kafkaHubOptions,
IKafkaMessenger kafkaMessenger,
IImpersonationHelper impersonateHelper,
IOptions<JsonSerializerOptions> serializerOptions,
ILogger<ReportController> logger,
Expand All @@ -96,6 +99,7 @@ IChesService ches
_kafkaProducer = kafkaProducer;
_kafkaOptions = kafkaOptions.Value;
_kafkaHubOptions = kafkaHubOptions.Value;
_kafkaMessenger = kafkaMessenger;
_impersonate = impersonateHelper;
_serializerOptions = serializerOptions.Value;
_logger = logger;
Expand Down Expand Up @@ -445,16 +449,31 @@ public async Task<IActionResult> AddContentToReportAsync(int id, [FromBody] IEnu
!report.SubscribersManyToMany.Any(s => s.IsSubscribed && s.UserId == user.Id) && // User is not subscribed to the report
!report.IsPublic) throw new NotAuthorizedException("Not authorized to review this report"); // Report is not public

var result = await _reportService.AddContentToReportAsync(id, user.Id, content.Select((c) => (Entities.ReportInstanceContent)c)) ?? throw new NoContentException("Report does not exist");
var addContent = content.Select((c) => (Entities.ReportInstanceContent)c);
if (addContent.Any())
{
var result = await _reportService.AddContentToReportAsync(id, user.Id, addContent) ?? throw new NoContentException("Report does not exist");

var instances = _reportService.GetLatestInstances(id, user.Id);
var currentInstance = instances.FirstOrDefault() ?? throw new InvalidOperationException("Unable to add content to a report without an instance");
currentInstance.ContentManyToMany.Clear();
currentInstance.ContentManyToMany.AddRange(_reportInstanceService.GetContentForInstance(currentInstance.Id));
result.Instances.Clear();
result.Instances.AddRange(instances);
var instances = _reportService.GetLatestInstances(id, user.Id);
var currentInstance = instances.FirstOrDefault() ?? throw new InvalidOperationException("Unable to add content to a report without an instance");
currentInstance.ContentManyToMany.Clear();
currentInstance.ContentManyToMany.AddRange(_reportInstanceService.GetContentForInstance(currentInstance.Id));
result.Instances.Clear();
result.Instances.AddRange(instances);

return new JsonResult(new ReportModel(result, _serializerOptions));
var ownerId = result.OwnerId ?? currentInstance.OwnerId;
if (ownerId.HasValue)
{
user = _userService.FindById(ownerId.Value) ?? throw new NotAuthorizedException();
await _kafkaMessenger.SendMessageAsync(
_kafkaHubOptions.HubTopic,
new KafkaHubMessage(HubEvent.SendUser, user.Username, new KafkaInvocationMessage(MessageTarget.ReportStatus, new[] { new ReportMessageModel(currentInstance) }))
);
}
return new JsonResult(new ReportModel(result, _serializerOptions));
}

return new JsonResult(new ReportModel(report, _serializerOptions));
}

/// <summary>
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion app/editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"redux-logger": "3.0.6",
"styled-components": "6.1.11",
"stylis": "4.3.2",
"tno-core": "0.1.148"
"tno-core": "0.1.149"
},
"devDependencies": {
"@simbathesailor/use-what-changed": "2.0.0",
Expand Down
10 changes: 5 additions & 5 deletions app/editor/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11009,7 +11009,7 @@ __metadata:
sass-extract-loader: 1.1.0
styled-components: 6.1.11
stylis: 4.3.2
tno-core: 0.1.148
tno-core: 0.1.149
typescript: 4.9.5
languageName: unknown
linkType: soft
Expand Down Expand Up @@ -15184,9 +15184,9 @@ __metadata:
languageName: node
linkType: hard

"tno-core@npm:0.1.148":
version: 0.1.148
resolution: "tno-core@npm:0.1.148"
"tno-core@npm:0.1.149":
version: 0.1.149
resolution: "tno-core@npm:0.1.149"
dependencies:
"@elastic/elasticsearch": ^8.13.1
"@fortawesome/free-solid-svg-icons": ^6.4.2
Expand Down Expand Up @@ -15219,7 +15219,7 @@ __metadata:
styled-components: ^6.1.11
stylis: ^4.3.2
yup: ^1.1.1
checksum: 3210b1243a79473ebe30e508e187c11d7d4dae85cb7ee3d2b0ca81431fd22440eee76d3f538cbc78788b4e5cdaa60edab9c10031d136b28e7cbaeefbb1dfeec5
checksum: fa2d5b34006e0fa08d5530ab9109680bf071e09e76db6d74be6ae1367ae38b292fb5be616948e30b041aa57dfe5c146a441161ee4f07a4a665ba05edd13a9dc6
languageName: node
linkType: hard

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion app/subscriber/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"sheetjs": "file:packages/xlsx-0.20.1.tgz",
"styled-components": "6.1.11",
"stylis": "4.3.2",
"tno-core": "0.1.148"
"tno-core": "0.1.149"
},
"devDependencies": {
"@testing-library/jest-dom": "6.4.5",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createContext, ReactNode, useState } from 'react';
import React from 'react';
import { useApp, useReports } from 'store/hooks';
import { useApp, useReports, useReportSync } from 'store/hooks';
import { useProfileStore } from 'store/slices';

import { defaultValueListContext } from './constants';
Expand All @@ -23,6 +23,7 @@ export const ContentListProvider: React.FC<IContentListProviderProps> = ({ child
// Make a request to reports to determine what content is in a report.
const [, { getAllContentInMyReports }] = useReports();
const [, { storeReportContent }] = useProfileStore();
useReportSync();

const [groupBy, setGroupBy] = useState<IGroupByState>('source');

Expand Down
1 change: 1 addition & 0 deletions app/subscriber/src/store/hooks/subscriber/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export * from './useNavigateAndScroll';
export * from './useProducts';
export * from './useReportInstances';
export * from './useReports';
export * from './useReportSync';
export * from './useReportTemplates';
export * from './useSystemMessages';
export * from './useUsers';
Expand Down
55 changes: 55 additions & 0 deletions app/subscriber/src/store/hooks/subscriber/useReportSync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react';
import { useProfileStore } from 'store/slices';
import { IReportMessageModel, MessageTargetKey, useApiSubscriberReportInstances } from 'tno-core';

import { useApiHub } from '../signalr';

/**
* Hook provides a singleton way to ensure my reports are synced across tabs.
*/
export const useReportSync = () => {
const { getReportInstance } = useApiSubscriberReportInstances();
const hub = useApiHub();
const [{ myReports }, { storeMyReports }] = useProfileStore();

// When a report instance has been updated a message will be received.
const handleUpdateReportInstance = React.useCallback(
async (message: IReportMessageModel) => {
try {
const report = myReports.find((r) => r.id === message.reportId);
const instance = report?.instances.length ? report.instances[0] : undefined;

// Only fetch the latest if the current report instance is older, or doesn't exist.
if (report && (!instance || instance.version !== message.version)) {
const response = await getReportInstance(message.id, true);
if (response.status === 200 && response.data) {
const instance = response.data;
storeMyReports((reports) => {
let addInstance = true;
let instances = report.instances.map((i) => {
if (i.id === message.id) {
addInstance = false;
return instance;
}
return i;
});
if (addInstance) instances = [instance, ...instances];
const results = reports.map((r) =>
r.id === report.id
? {
...report,
instances,
}
: r,
);
return results;
});
}
}
} catch {}
},
[getReportInstance, myReports, storeMyReports],
);

hub.useHubEffect(MessageTargetKey.ReportStatus, handleUpdateReportInstance);
};
10 changes: 5 additions & 5 deletions app/subscriber/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10665,7 +10665,7 @@ __metadata:
sheetjs: "file:packages/xlsx-0.20.1.tgz"
styled-components: 6.1.11
stylis: 4.3.2
tno-core: 0.1.148
tno-core: 0.1.149
typescript: 4.9.5
languageName: unknown
linkType: soft
Expand Down Expand Up @@ -14698,9 +14698,9 @@ __metadata:
languageName: node
linkType: hard

"tno-core@npm:0.1.148":
version: 0.1.148
resolution: "tno-core@npm:0.1.148"
"tno-core@npm:0.1.149":
version: 0.1.149
resolution: "tno-core@npm:0.1.149"
dependencies:
"@elastic/elasticsearch": ^8.13.1
"@fortawesome/free-solid-svg-icons": ^6.4.2
Expand Down Expand Up @@ -14733,7 +14733,7 @@ __metadata:
styled-components: ^6.1.11
stylis: ^4.3.2
yup: ^1.1.1
checksum: 3210b1243a79473ebe30e508e187c11d7d4dae85cb7ee3d2b0ca81431fd22440eee76d3f538cbc78788b4e5cdaa60edab9c10031d136b28e7cbaeefbb1dfeec5
checksum: fa2d5b34006e0fa08d5530ab9109680bf071e09e76db6d74be6ae1367ae38b292fb5be616948e30b041aa57dfe5c146a441161ee4f07a4a665ba05edd13a9dc6
languageName: node
linkType: hard

Expand Down
20 changes: 13 additions & 7 deletions libs/net/dal/Services/ReportService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -660,18 +660,23 @@ public static ReportInstanceContent[] OrderBySectionField(IEnumerable<ReportInst

// Add new content that does not already exist in the report and only for valid sections.
var addContent = content.Where(c => report.Sections.Any(s => s.Name == c.SectionName) && !instance.ContentManyToMany.Any(ic => ic.SectionName == c.SectionName && ic.ContentId == c.ContentId));
instance.ContentManyToMany.AddRange(addContent);
if (addContent.Any())
{
instance.ContentManyToMany.AddRange(addContent);

instance = _reportInstanceService.AddAndSave(instance);
report.Instances.Add(instance);
instance = _reportInstanceService.AddAndSave(instance);
report.Instances.Add(instance);
}
}
else
{
// Add new content that does not already exist in the report and only for valid sections.
var addContent = content.Where(c => report.Sections.Any(s => s.Name == c.SectionName) && !instance.ContentManyToMany.Any(ic => ic.SectionName == c.SectionName && ic.ContentId == c.ContentId));
instance.ContentManyToMany.AddRange(addContent);

instance = _reportInstanceService.UpdateAndSave(instance, true);
if (addContent.Any())
{
instance.ContentManyToMany.AddRange(addContent);
instance = _reportInstanceService.UpdateAndSave(instance, true);
}
}

return report;
Expand Down Expand Up @@ -1091,7 +1096,8 @@ public IEnumerable<long> GetRelatedReportInstanceContentToExclude(int reportId)
try
{
this.Context.SaveChanges();
} catch (Exception ex)
}
catch (Exception ex)
{
this.Logger.LogError(ex, $"ReportService - ClearFoldersInReport Report Id: {report.Id} throws exception.");
throw;
Expand Down
2 changes: 1 addition & 1 deletion libs/npm/core/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "tno-core",
"description": "TNO shared library",
"version": "0.1.148",
"version": "0.1.149",
"homepage": "https://github.com/bcgov/tno",
"license": "Apache-2.0",
"files": [
Expand Down
4 changes: 2 additions & 2 deletions libs/npm/core/src/hooks/api/interfaces/IReportMessageModel.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IUserModel, ReportStatusName } from '..';
import { IAuditColumnsModel, IUserModel, ReportStatusName } from '..';

export interface IReportMessageModel {
export interface IReportMessageModel extends IAuditColumnsModel {
id: number;
reportId: number;
subject: string;
Expand Down

0 comments on commit 9eca00c

Please sign in to comment.