mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-30 03:00:57 +00:00
refactor: move shortsyntax effects to their own file
This commit is contained in:
parent
0da1a080c6
commit
2eda702642
3 changed files with 190 additions and 172 deletions
186
src/app/features/tasks/store/short-syntax.effects.ts
Normal file
186
src/app/features/tasks/store/short-syntax.effects.ts
Normal 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,
|
||||
) {}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue