-
-
Notifications
You must be signed in to change notification settings - Fork 219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
5710 add breadcrumbs to tasks lists #7757
Changes from 86 commits
cdcf4da
7538e37
eceb40e
ea0fbfc
d56e881
9523922
f15dc81
2660772
2ddc752
de97add
c6152dd
884e3f4
3fe346d
0d189c2
ed07e1c
cfb46e1
7915562
dac433f
dd23303
7d65415
00e507a
fcfdc5a
cacd0e8
65a130d
81a7bd4
a953159
7698d0a
cb066fa
30faef1
81dcd93
ae37aed
8344348
ec1c8bc
b0e05d9
7a31fcb
4f66eb3
68900b2
ca5627c
4aaed95
9e083f0
ad8a21e
8998312
ec2b459
3f53451
4a52c83
981e992
6011687
4d0d319
b54f13d
70137c5
172b152
eaa98ef
5741c82
683f668
8be9c28
e8f4199
4939ebb
f480f7c
1acc294
63add58
7169639
294ae76
af6c515
03915ef
cb1b555
d6a3137
2602efe
03bd416
a38ded8
ff93496
c5bd08a
6d7cb7f
fbc6bc6
5b64c06
46441e7
52fc587
09ef7e5
efeb2fc
9f97525
dae884c
0098a58
5d3648e
5b5fa10
bcf9870
6beae56
8a60b20
919d64f
247877d
6414d8b
d6eec6c
1476213
5430cc3
49fc243
1ecad5d
bdf4065
4992734
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,19 +13,25 @@ import { Selectors } from '@mm-selectors/index'; | |
import { TelemetryService } from '@mm-services/telemetry.service'; | ||
import { TourService } from '@mm-services/tour.service'; | ||
import { GlobalActions } from '@mm-actions/global'; | ||
import { LineageModelGeneratorService } from '@mm-services/lineage-model-generator.service'; | ||
import { UserContactService } from '@mm-services/user-contact.service'; | ||
import { SessionService } from '@mm-services/session.service'; | ||
|
||
@Component({ | ||
templateUrl: './tasks.component.html', | ||
}) | ||
export class TasksComponent implements OnInit, OnDestroy { | ||
constructor( | ||
private store:Store, | ||
private changesService:ChangesService, | ||
private contactTypesService:ContactTypesService, | ||
private rulesEngineService:RulesEngineService, | ||
private telemetryService:TelemetryService, | ||
private tourService:TourService, | ||
private route:ActivatedRoute, | ||
private store: Store, | ||
private changesService: ChangesService, | ||
private contactTypesService: ContactTypesService, | ||
private rulesEngineService: RulesEngineService, | ||
private telemetryService: TelemetryService, | ||
private tourService: TourService, | ||
private route: ActivatedRoute, | ||
private lineageModelGeneratorService: LineageModelGeneratorService, | ||
private userContactService: UserContactService, | ||
private sessionService: SessionService, | ||
) { | ||
this.tasksActions = new TasksActions(store); | ||
this.globalActions = new GlobalActions(store); | ||
|
@@ -41,6 +47,7 @@ export class TasksComponent implements OnInit, OnDestroy { | |
hasTasks; | ||
loading; | ||
tasksDisabled; | ||
currentLevel; | ||
|
||
private tasksLoaded; | ||
private debouncedReload; | ||
|
@@ -96,7 +103,10 @@ export class TasksComponent implements OnInit, OnDestroy { | |
this.error = false; | ||
this.hasTasks = false; | ||
this.loading = true; | ||
this.debouncedReload = _debounce(this.refreshTasks.bind(this), 1000, { maxWait: 10 * 1000 }); | ||
this.debouncedReload = _debounce(this.refreshTasks.bind(this), 1000, {maxWait: 10 * 1000}); | ||
|
||
this.currentLevel = this.sessionService.isOnlineOnly() ? Promise.resolve() : this.getCurrentLineageLevel(); | ||
|
||
this.refreshTasks(); | ||
|
||
this.tourService.startIfNeeded(this.route.snapshot); | ||
|
@@ -118,50 +128,91 @@ export class TasksComponent implements OnInit, OnDestroy { | |
|
||
private hydrateEmissions(taskDocs) { | ||
return taskDocs.map(taskDoc => { | ||
const emission = { ...taskDoc.emission }; | ||
const emission = {...taskDoc.emission}; | ||
const dueDate = moment(emission.dueDate, 'YYYY-MM-DD'); | ||
emission.date = new Date(dueDate.valueOf()); | ||
emission.overdue = dueDate.isBefore(moment()); | ||
emission.owner = taskDoc.owner; | ||
|
||
emission.forId = taskDoc.forId ? taskDoc.forId : taskDoc.owner; | ||
return emission; | ||
}); | ||
} | ||
|
||
private refreshTasks() { | ||
const telemetryData:any = { | ||
start: Date.now(), | ||
}; | ||
|
||
return this.rulesEngineService | ||
.isEnabled() | ||
.then(isEnabled => { | ||
this.tasksDisabled = !isEnabled; | ||
return isEnabled ? this.rulesEngineService.fetchTaskDocsForAllContacts() : []; | ||
}) | ||
.then(taskDocs => { | ||
this.hasTasks = taskDocs.length > 0; | ||
this.loading = false; | ||
this.tasksActions.setTasksList(this.hydrateEmissions(taskDocs)); | ||
if (!this.tasksLoaded) { | ||
this.tasksActions.setTasksLoaded(true); | ||
private async refreshTasks() { | ||
try { | ||
const telemetryData: any = { | ||
start: Date.now(), | ||
}; | ||
|
||
const isEnabled = await this.rulesEngineService.isEnabled(); | ||
this.tasksDisabled = !isEnabled; | ||
const taskDocs = isEnabled ? await this.rulesEngineService.fetchTaskDocsForAllContacts() : []; | ||
|
||
this.hasTasks = taskDocs.length > 0; | ||
this.loading = false; | ||
|
||
const hydratedTasks = await this.hydrateEmissions(taskDocs) || []; | ||
const subjects = await this.getLineagesFromTaskDocs(hydratedTasks); | ||
if (subjects?.size) { | ||
const userLineageLevel = await this.currentLevel; | ||
for (const task of hydratedTasks) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In theory the Another option is to await 1 time first and send over the currentLevel to the
And the @jkuester @elvisdorkenoo what do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I like the second option, it would make me passing over |
||
task.lineage = await this.getTaskLineage(subjects, task, userLineageLevel); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pretty sure we don't need to await this call. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and you can use for each as in the sample here. |
||
} | ||
} | ||
|
||
this.tasksActions.setTasksList(hydratedTasks); | ||
|
||
telemetryData.end = Date.now(); | ||
const telemetryEntryName = !this.tasksLoaded ? `tasks:load`: `tasks:refresh`; | ||
this.telemetryService.record(telemetryEntryName, telemetryData.end - telemetryData.start); | ||
}) | ||
.catch(err => { | ||
console.error('Error getting tasks for all contacts', err); | ||
|
||
this.error = true; | ||
this.loading = false; | ||
this.hasTasks = false; | ||
this.tasksActions.setTasksList([]); | ||
}); | ||
if (!this.tasksLoaded) { | ||
this.tasksActions.setTasksLoaded(true); | ||
} | ||
|
||
telemetryData.end = Date.now(); | ||
const telemetryEntryName = !this.tasksLoaded ? `tasks:load` : `tasks:refresh`; | ||
this.telemetryService.record(telemetryEntryName, telemetryData.end - telemetryData.start); | ||
|
||
} catch (exception) { | ||
console.error('Error getting tasks for all contacts', exception); | ||
this.error = true; | ||
this.loading = false; | ||
this.hasTasks = false; | ||
this.tasksActions.setTasksList([]); | ||
} | ||
} | ||
|
||
listTrackBy(index, task) { | ||
return task?._id; | ||
} | ||
|
||
private getCurrentLineageLevel() { | ||
return this.userContactService.get().then(user => user?.parent?.name); | ||
} | ||
|
||
private getLineagesFromTaskDocs(taskDocs) { | ||
const ids = [...new Set(taskDocs.map(task => task.forId))]; | ||
return this.lineageModelGeneratorService | ||
.reportSubjects(ids) | ||
.then(subjects => new Map(subjects.map(subject => [subject._id, subject.lineage]))); | ||
} | ||
|
||
private getTaskLineage(subjects, task, userLineageLevel) { | ||
if (!subjects?.size) { | ||
return; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor, but this check is unnecessary since you have done it already above. |
||
const lineage = subjects | ||
.get(task.forId) | ||
?.map(lineage => lineage?.name); | ||
return this.cleanAndRemoveCurrentLineage(lineage, userLineageLevel); | ||
} | ||
|
||
private async cleanAndRemoveCurrentLineage(lineage, userLineageLevel) { | ||
if(!lineage?.length){ | ||
return; | ||
} | ||
lineage = lineage.filter(level => level); | ||
const item = lineage[lineage.length - 1]; | ||
if (item === userLineageLevel) { | ||
lineage.pop(); | ||
} | ||
return lineage; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we sure that we are not going to inadvertently trigger some additional logic by setting the
forId
toowner
?I am not sure exactly what the difference is between the two fields anyway, but I am a little worried that this could have unintended consequences...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elvisdorkenoo - To play safe, you can:
emission.owner
already defined and available.emission.forId
and don't default it totask.owner
because it's already expose inemission.owner
.getLineagesFromTaskDocs
check for both properties:const ids = [...new Set(taskDocs.map(task => task.forId || task.owner))];
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
task => task.forId || task.owner
is actually what I've before changing it this way when I got the confirmation that when it's set, task.forId always equals task.owner. But yeah let's play it safe.