refactor: move shortsyntax effects to their own file

This commit is contained in:
Johannes Millan 2024-02-02 11:41:57 +01:00
parent 0da1a080c6
commit 2eda702642
3 changed files with 190 additions and 172 deletions

View file

@ -0,0 +1,186 @@
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import {
addTask,
moveToOtherProject,
scheduleTask,
updateTask,
updateTaskTags,
} from './task.actions';
import {
concatMap,
filter,
map,
mapTo,
mergeMap,
tap,
withLatestFrom,
} from 'rxjs/operators';
import { TaskReminderOptionId } from '../task.model';
import { GlobalConfigService } from '../../config/global-config.service';
import { unique } from '../../../util/unique';
import { TaskService } from '../task.service';
import { EMPTY, Observable, of } from 'rxjs';
import { ProjectService } from '../../project/project.service';
import { TagService } from '../../tag/tag.service';
import { shortSyntax } from '../short-syntax.util';
import { remindOptionToMilliseconds } from '../util/remind-option-to-milliseconds';
import { environment } from '../../../../environments/environment';
import { SnackService } from '../../../core/snack/snack.service';
import { T } from '../../../t.const';
@Injectable()
export class ShortSyntaxEffects {
shortSyntax$: any = createEffect(() =>
this._actions$.pipe(
ofType(addTask, updateTask),
filter((action): boolean => {
if (action.isIgnoreShortSyntax) {
return false;
}
if (action.type !== updateTask.type) {
return true;
}
const changeProps = Object.keys(action.task.changes);
// we only want to execute this for task title updates
return changeProps.length === 1 && changeProps[0] === 'title';
}),
// dirty fix to execute this after setDefaultProjectId$ effect
concatMap((originalAction): Observable<any> => {
return this._taskService.getByIdOnce$(originalAction.task.id as string).pipe(
map((task) => ({
task,
originalAction,
})),
);
}),
withLatestFrom(
this._tagService.tags$,
this._projectService.list$,
this._globalConfigService.misc$.pipe(
map((misc) => misc.defaultProjectId),
concatMap((defaultProjectId) =>
defaultProjectId
? this._projectService.getByIdOnce$(defaultProjectId).pipe(
tap((project) => {
if (!project) {
// to avoid further data inconsistencies
throw new Error('Default Project not found');
}
}),
mapTo(defaultProjectId),
)
: of(defaultProjectId),
),
),
),
mergeMap(([{ task, originalAction }, tags, projects, defaultProjectId]) => {
const r = shortSyntax(task, tags, projects);
if (environment.production) {
console.log('shortSyntax', r);
}
const isAddDefaultProjectIfNecessary: boolean =
!!defaultProjectId &&
!task.projectId &&
!task.parentId &&
task.projectId !== defaultProjectId &&
originalAction.type === addTask.type;
if (!r) {
if (isAddDefaultProjectIfNecessary) {
return [
moveToOtherProject({
task,
targetProjectId: defaultProjectId as string,
}),
];
}
return EMPTY;
}
const actions: any[] = [];
const tagIds: string[] = [...(r.taskChanges.tagIds || task.tagIds)];
const { taskChanges } = r;
actions.push(
updateTask({
task: {
id: task.id,
changes: r.taskChanges,
},
isIgnoreShortSyntax: true,
}),
);
if (taskChanges.plannedAt && !taskChanges.reminderId) {
const { plannedAt } = taskChanges;
const schedule = scheduleTask({
task,
plannedAt,
remindAt: remindOptionToMilliseconds(plannedAt, TaskReminderOptionId.AtStart),
isMoveToBacklog: false,
});
actions.push(schedule);
}
if (r.projectId && r.projectId !== task.projectId && !task.parentId) {
if (task.repeatCfgId) {
this._snackService.open({
ico: 'warning',
msg: T.F.TASK.S.CANNOT_ASSIGN_PROJECT_FOR_REPEATABLE_TASK,
});
} else {
actions.push(
moveToOtherProject({
task,
targetProjectId: r.projectId,
}),
);
}
} else if (isAddDefaultProjectIfNecessary) {
actions.push(
moveToOtherProject({
task,
targetProjectId: defaultProjectId as string,
}),
);
}
if (r.newTagTitles.length) {
r.newTagTitles.forEach((newTagTitle) => {
const { action, id } = this._tagService.getAddTagActionAndId({
title: newTagTitle,
});
tagIds.push(id);
actions.push(action);
});
}
if (tagIds && tagIds.length) {
const isEqualTags = JSON.stringify(tagIds) === JSON.stringify(task.tagIds);
if (!task.tagIds) {
throw new Error('Task Old TagIds need to be passed');
}
if (!isEqualTags) {
actions.push(
updateTaskTags({
task,
newTagIds: unique(tagIds),
oldTagIds: task.tagIds,
}),
);
}
}
return actions;
}),
),
);
constructor(
private _actions$: Actions,
private _taskService: TaskService,
private _tagService: TagService,
private _projectService: ProjectService,
private _globalConfigService: GlobalConfigService,
private _snackService: SnackService,
) {}
}

View file

@ -1,34 +1,15 @@
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import {
addTask,
addTimeSpent,
moveToArchive,
moveToOtherProject,
restoreTask,
scheduleTask,
updateTask,
updateTaskTags,
} from './task.actions';
import {
concatMap,
filter,
first,
map,
mapTo,
mergeMap,
switchMap,
tap,
withLatestFrom,
} from 'rxjs/operators';
import { concatMap, filter, first, map, switchMap, tap } from 'rxjs/operators';
import { PersistenceService } from '../../../core/persistence/persistence.service';
import {
Task,
TaskArchive,
TaskCopy,
TaskReminderOptionId,
TaskWithSubTasks,
} from '../task.model';
import { Task, TaskArchive, TaskCopy, TaskWithSubTasks } from '../task.model';
import { ReminderService } from '../../reminder/reminder.service';
import { moveTaskInTodayList } from '../../work-context/store/work-context-meta.actions';
import { taskAdapter } from './task.adapter';
@ -39,11 +20,6 @@ import { unique } from '../../../util/unique';
import { TaskService } from '../task.service';
import { EMPTY, Observable, of } from 'rxjs';
import { createEmptyEntity } from '../../../util/create-empty-entity';
import { ProjectService } from '../../project/project.service';
import { TagService } from '../../tag/tag.service';
import { shortSyntax } from '../short-syntax.util';
import { remindOptionToMilliseconds } from '../util/remind-option-to-milliseconds';
import { environment } from '../../../../environments/environment';
import { moveProjectTaskToTodayList } from '../../project/store/project.actions';
import { SnackService } from '../../../core/snack/snack.service';
import { T } from '../../../t.const';
@ -238,156 +214,10 @@ export class TaskRelatedModelEffects {
),
);
shortSyntax$: any = createEffect(() =>
this._actions$.pipe(
ofType(addTask, updateTask),
filter((action): boolean => {
if (action.isIgnoreShortSyntax) {
return false;
}
if (action.type !== updateTask.type) {
return true;
}
const changeProps = Object.keys(action.task.changes);
// we only want to execute this for task title updates
return changeProps.length === 1 && changeProps[0] === 'title';
}),
// dirty fix to execute this after setDefaultProjectId$ effect
concatMap((originalAction): Observable<any> => {
return this._taskService.getByIdOnce$(originalAction.task.id as string).pipe(
map((task) => ({
task,
originalAction,
})),
);
}),
withLatestFrom(
this._tagService.tags$,
this._projectService.list$,
this._globalConfigService.misc$.pipe(
map((misc) => misc.defaultProjectId),
concatMap((defaultProjectId) =>
defaultProjectId
? this._projectService.getByIdOnce$(defaultProjectId).pipe(
tap((project) => {
if (!project) {
// to avoid further data inconsistencies
throw new Error('Default Project not found');
}
}),
mapTo(defaultProjectId),
)
: of(defaultProjectId),
),
),
),
mergeMap(([{ task, originalAction }, tags, projects, defaultProjectId]) => {
const r = shortSyntax(task, tags, projects);
if (environment.production) {
console.log('shortSyntax', r);
}
const isAddDefaultProjectIfNecessary: boolean =
!!defaultProjectId &&
!task.projectId &&
!task.parentId &&
task.projectId !== defaultProjectId &&
originalAction.type === addTask.type;
if (!r) {
if (isAddDefaultProjectIfNecessary) {
return [
moveToOtherProject({
task,
targetProjectId: defaultProjectId as string,
}),
];
}
return EMPTY;
}
const actions: any[] = [];
const tagIds: string[] = [...(r.taskChanges.tagIds || task.tagIds)];
const { taskChanges } = r;
actions.push(
updateTask({
task: {
id: task.id,
changes: r.taskChanges,
},
isIgnoreShortSyntax: true,
}),
);
if (taskChanges.plannedAt && !taskChanges.reminderId) {
const { plannedAt } = taskChanges;
const schedule = scheduleTask({
task,
plannedAt,
remindAt: remindOptionToMilliseconds(plannedAt, TaskReminderOptionId.AtStart),
isMoveToBacklog: false,
});
actions.push(schedule);
}
if (r.projectId && r.projectId !== task.projectId && !task.parentId) {
if (task.repeatCfgId) {
this._snackService.open({
ico: 'warning',
msg: T.F.TASK.S.CANNOT_ASSIGN_PROJECT_FOR_REPEATABLE_TASK,
});
} else {
actions.push(
moveToOtherProject({
task,
targetProjectId: r.projectId,
}),
);
}
} else if (isAddDefaultProjectIfNecessary) {
actions.push(
moveToOtherProject({
task,
targetProjectId: defaultProjectId as string,
}),
);
}
if (r.newTagTitles.length) {
r.newTagTitles.forEach((newTagTitle) => {
const { action, id } = this._tagService.getAddTagActionAndId({
title: newTagTitle,
});
tagIds.push(id);
actions.push(action);
});
}
if (tagIds && tagIds.length) {
const isEqualTags = JSON.stringify(tagIds) === JSON.stringify(task.tagIds);
if (!task.tagIds) {
throw new Error('Task Old TagIds need to be passed');
}
if (!isEqualTags) {
actions.push(
updateTaskTags({
task,
newTagIds: unique(tagIds),
oldTagIds: task.tagIds,
}),
);
}
}
return actions;
}),
),
);
constructor(
private _actions$: Actions,
private _reminderService: ReminderService,
private _taskService: TaskService,
private _tagService: TagService,
private _projectService: ProjectService,
private _globalConfigService: GlobalConfigService,
private _persistenceService: PersistenceService,
private _snackService: SnackService,

View file

@ -34,6 +34,7 @@ import { DialogViewTaskRemindersComponent } from './dialog-view-task-reminders/d
import { TaskSummaryTablesComponent } from './task-summary-tables/task-summary-tables.component';
import { IS_ELECTRON } from '../../app.constants';
import { TasksByTagComponent } from './tasks-by-tag/tasks-by-tag.component';
import { ShortSyntaxEffects } from './store/short-syntax.effects';
@NgModule({
imports: [
@ -52,6 +53,7 @@ import { TasksByTagComponent } from './tasks-by-tag/tasks-by-tag.component';
TaskRelatedModelEffects,
TaskReminderEffects,
TaskUiEffects,
ShortSyntaxEffects,
...(IS_ELECTRON ? [TaskElectronEffects] : []),
]),
BetterDrawerModule,