refactor(issue): consolidate deleteIssueProvider actions to TaskSharedActions

Move deleteIssueProviders from IssueProviderActions to TaskSharedActions for
consistency with deleteIssueProvider. Both actions affect task state (unlinking
issue fields) and need meta-reducer handling.

- Add TaskSharedActions.deleteIssueProviders with taskIdsToUnlink support
- Remove unused IssueProviderActions.deleteIssueProvider/deleteIssueProviders
- Update issue-provider reducer to use new action
- Update meta-reducer to handle bulk task unlinking
- Update archive-operation-handler to use consolidated action
This commit is contained in:
Johannes Millan 2025-12-08 17:29:57 +01:00
parent 9a401169fa
commit 0fe28303b2
6 changed files with 27 additions and 37 deletions

View file

@ -13,7 +13,6 @@ import { TaskSharedActions } from '../../../../root-store/meta/task-shared.actio
import { flushYoungToOld } from '../../../../features/time-tracking/store/archive.actions';
import { deleteTag, deleteTags } from '../../../../features/tag/store/tag.actions';
import { TimeTrackingService } from '../../../../features/time-tracking/time-tracking.service';
import { IssueProviderActions } from '../../../../features/issue/store/issue-provider.actions';
describe('isArchiveAffectingAction', () => {
it('should return true for moveToArchive action', () => {
@ -57,7 +56,7 @@ describe('isArchiveAffectingAction', () => {
});
it('should return true for deleteIssueProviders action', () => {
const action = { type: IssueProviderActions.deleteIssueProviders.type };
const action = { type: TaskSharedActions.deleteIssueProviders.type };
expect(isArchiveAffectingAction(action)).toBe(true);
});
@ -493,7 +492,7 @@ describe('ArchiveOperationHandler', () => {
describe('deleteIssueProviders action', () => {
it('should unlink multiple issue providers from all archive tasks', async () => {
const action = {
type: IssueProviderActions.deleteIssueProviders.type,
type: TaskSharedActions.deleteIssueProviders.type,
ids: ['provider-1', 'provider-2', 'provider-3'],
meta: { isPersistent: true, isRemote: true },
} as unknown as PersistentAction;
@ -516,7 +515,7 @@ describe('ArchiveOperationHandler', () => {
it('should not call other handlers for deleteIssueProviders', async () => {
const action = {
type: IssueProviderActions.deleteIssueProviders.type,
type: TaskSharedActions.deleteIssueProviders.type,
ids: ['provider-1'],
meta: { isPersistent: true, isRemote: true },
} as unknown as PersistentAction;
@ -727,7 +726,7 @@ describe('ArchiveOperationHandler', () => {
);
const action = {
type: IssueProviderActions.deleteIssueProviders.type,
type: TaskSharedActions.deleteIssueProviders.type,
ids: ['provider-1', 'provider-2'],
meta: { isPersistent: true, isRemote: true },
} as unknown as PersistentAction;

View file

@ -12,7 +12,6 @@ import { Log } from '../../../log';
import { lazyInject } from '../../../../util/lazy-inject';
import { deleteTag, deleteTags } from '../../../../features/tag/store/tag.actions';
import { TimeTrackingService } from '../../../../features/time-tracking/time-tracking.service';
import { IssueProviderActions } from '../../../../features/issue/store/issue-provider.actions';
/**
* Action types that affect archive storage and require special handling.
@ -26,7 +25,7 @@ const ARCHIVE_AFFECTING_ACTION_TYPES: string[] = [
deleteTags.type,
TaskSharedActions.deleteTaskRepeatCfg.type,
TaskSharedActions.deleteIssueProvider.type,
IssueProviderActions.deleteIssueProviders.type,
TaskSharedActions.deleteIssueProviders.type,
];
/**
@ -130,7 +129,7 @@ export class ArchiveOperationHandler {
await this._handleDeleteIssueProvider(action);
break;
case IssueProviderActions.deleteIssueProviders.type:
case TaskSharedActions.deleteIssueProviders.type:
await this._handleDeleteIssueProviders(action);
break;
}
@ -269,8 +268,7 @@ export class ArchiveOperationHandler {
* Called when receiving a remote deleteIssueProviders operation.
*/
private async _handleDeleteIssueProviders(action: PersistentAction): Promise<void> {
const ids = (action as ReturnType<typeof IssueProviderActions.deleteIssueProviders>)
.ids;
const ids = (action as ReturnType<typeof TaskSharedActions.deleteIssueProviders>).ids;
for (const issueProviderId of ids) {
await this._getTaskArchiveService().unlinkIssueProviderFromArchiveTasks(
issueProviderId,

View file

@ -57,27 +57,6 @@ export const IssueProviderActions = createActionGroup({
} satisfies PersistentActionMeta,
}),
'Delete IssueProvider': (providerProps: { id: string }) => ({
...providerProps,
meta: {
isPersistent: true,
entityType: 'ISSUE_PROVIDER',
entityId: providerProps.id,
opType: OpType.Delete,
} satisfies PersistentActionMeta,
}),
'Delete IssueProviders': (providerProps: { ids: string[] }) => ({
...providerProps,
meta: {
isPersistent: true,
entityType: 'ISSUE_PROVIDER',
entityIds: providerProps.ids,
opType: OpType.Delete,
isBulk: true,
} satisfies PersistentActionMeta,
}),
// Internal cleanup action - no persistence
'Clear IssueProviders': emptyProps(),
},

View file

@ -34,6 +34,9 @@ export const issueProviderReducer = createReducer(
on(TaskSharedActions.deleteIssueProvider, (state, { issueProviderId }) =>
adapter.removeOne(issueProviderId, state),
),
on(TaskSharedActions.deleteIssueProviders, (state, { ids }) =>
adapter.removeMany(ids, state),
),
// -----------
on(IssueProviderActions.addIssueProvider, (state, action) =>
@ -54,12 +57,6 @@ export const issueProviderReducer = createReducer(
on(IssueProviderActions.updateIssueProviders, (state, action) =>
adapter.updateMany(action.issueProviders, state),
),
on(IssueProviderActions.deleteIssueProvider, (state, action) =>
adapter.removeOne(action.id, state),
),
on(IssueProviderActions.deleteIssueProviders, (state, action) =>
adapter.removeMany(action.ids, state),
),
on(IssueProviderActions.loadIssueProviders, (state, action) =>
adapter.setAll(action.issueProviders, state),
),

View file

@ -63,6 +63,12 @@ const createActionHandlers = (state: RootState, action: Action): ActionHandlerMa
>;
return handleDeleteIssueProvider(state, taskIdsToUnlink);
},
[TaskSharedActions.deleteIssueProviders.type]: () => {
const { taskIdsToUnlink } = action as ReturnType<
typeof TaskSharedActions.deleteIssueProviders
>;
return handleDeleteIssueProvider(state, taskIdsToUnlink);
},
});
export const issueProviderSharedMetaReducer: MetaReducer = (

View file

@ -279,6 +279,17 @@ export const TaskSharedActions = createActionGroup({
} satisfies PersistentActionMeta,
}),
deleteIssueProviders: (props: { ids: string[]; taskIdsToUnlink: string[] }) => ({
...props,
meta: {
isPersistent: true,
entityType: 'ISSUE_PROVIDER',
entityIds: props.ids,
opType: OpType.Delete,
isBulk: true,
} satisfies PersistentActionMeta,
}),
// Task Repeat Config Management
deleteTaskRepeatCfg: (props: {
taskRepeatCfgId: string;