Skip to content

Commit

Permalink
feat: add angular cdk for project list
Browse files Browse the repository at this point in the history
  • Loading branch information
johannesjo committed Sep 3, 2024
1 parent fa7ed4a commit 3139a1f
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 44 deletions.
1 change: 1 addition & 0 deletions src/app/app.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const IS_ELECTRON = navigator.userAgent.toLowerCase().indexOf(' electron/
export const TRACKING_INTERVAL = 1000;

export const MODEL_VERSION_KEY = '__modelVersion';
export const DRAG_DELAY_FOR_TOUCH = 75;

import '@angular/common/locales/global/en';
import '@angular/common/locales/global/es';
Expand Down
13 changes: 10 additions & 3 deletions src/app/core-ui/side-nav/side-nav.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,25 @@

<div
[@standardList]="projectList?.length"
[dragulaModel]="projectList"
[dragula]="PROJECTS_SIDE_NAV"
cdkDropList
(cdkDropListDropped)="dropOnProjectList(projectList, $event)"
>
@for (project of projectList; track project.id) {
<!---->@if (!project.isHiddenFromMenu) {
<side-nav-item
#menuEntry
cdkDrag
[cdkDragData]="project"
[cdkDragStartDelay]="IS_TOUCH_PRIMARY ? DRAG_DELAY_FOR_TOUCH : 0"
(keydown)="checkFocusProject($event)"
*ngFor="let project of projectList; trackBy: trackById;"
[workContext]="project"
[type]="WorkContextType.PROJECT"
[defaultIcon]="'folder_special'"
[activeWorkContextId]="activeWorkContextId"
></side-nav-item>
}
<!---->
}
</div>

<button
Expand Down
65 changes: 29 additions & 36 deletions src/app/core-ui/side-nav/side-nav.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { T } from '../../t.const';
import { DialogCreateProjectComponent } from '../../features/project/dialogs/create-project/dialog-create-project.component';
import { Project } from '../../features/project/project.model';
import { MatDialog } from '@angular/material/dialog';
import { THEME_COLOR_MAP } from '../../app.constants';
import { DRAG_DELAY_FOR_TOUCH } from '../../app.constants';
import { DragulaService } from 'ng2-dragula';
import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs';
import { WorkContextService } from '../../features/work-context/work-context.service';
Expand All @@ -30,12 +30,13 @@ import { LayoutService } from '../layout/layout.service';
import { TaskService } from '../../features/tasks/task.service';
import { LS } from '../../core/persistence/storage-keys.const';
import { TODAY_TAG } from '../../features/tag/tag.const';
import { DialogTimelineSetupComponent } from '../../features/schedule/dialog-timeline-setup/dialog-timeline-setup.component';
import { TourId } from '../../features/shepherd/shepherd-steps.const';
import { ShepherdService } from '../../features/shepherd/shepherd.service';
import { getGithubErrorUrl } from 'src/app/core/error-handler/global-error-handler.util';
import { IS_MOUSE_PRIMARY } from '../../util/is-mouse-primary';
import { IS_MOUSE_PRIMARY, IS_TOUCH_PRIMARY } from '../../util/is-mouse-primary';
import { GlobalConfigService } from '../../features/config/global-config.service';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { moveItemBeforeItem } from '../../util/move-item-before-item';

@Component({
selector: 'side-nav',
Expand All @@ -47,6 +48,9 @@ import { GlobalConfigService } from '../../features/config/global-config.service
export class SideNavComponent implements OnDestroy {
@ViewChildren('menuEntry') navEntries?: QueryList<MatMenuItem>;
IS_MOUSE_PRIMARY = IS_MOUSE_PRIMARY;
IS_TOUCH_PRIMARY = IS_TOUCH_PRIMARY;
DRAG_DELAY_FOR_TOUCH = DRAG_DELAY_FOR_TOUCH;

keyboardFocusTimeout?: number;
@ViewChild('projectExpandBtn', { read: ElementRef }) projectExpandBtn?: ElementRef;
isProjectsExpanded: boolean = this.fetchProjectListState();
Expand Down Expand Up @@ -79,7 +83,6 @@ export class SideNavComponent implements OnDestroy {
),
);
T: typeof T = T;
readonly PROJECTS_SIDE_NAV: string = 'PROJECTS_SIDE_NAV';
readonly TAG_SIDE_NAV: string = 'TAG_SIDE_NAV';
activeWorkContextId?: string | null;
WorkContextType: typeof WorkContextType = WorkContextType;
Expand All @@ -103,17 +106,6 @@ export class SideNavComponent implements OnDestroy {
private readonly _shepherdService: ShepherdService,
private readonly _globalConfigService: GlobalConfigService,
) {
this._dragulaService.createGroup(this.PROJECTS_SIDE_NAV, {
direction: 'vertical',
moves: (el, container, handle) => {
return (
this.isProjectsExpanded &&
!!handle &&
handle.className.indexOf &&
handle.className.indexOf('drag-handle') > -1
);
},
});
this._dragulaService.createGroup(this.TAG_SIDE_NAV, {
direction: 'vertical',
moves: (el, container, handle) => {
Expand All @@ -132,16 +124,6 @@ export class SideNavComponent implements OnDestroy {
),
);

this._subs.add(
this._dragulaService
.dropModel(this.PROJECTS_SIDE_NAV)
.subscribe(({ targetModel }) => {
// const {target, source, targetModel, item} = params;
const targetNewIds = targetModel.map((project: Project) => project.id);
this.projectService.updateOrder(targetNewIds);
}),
);

this._subs.add(
this._dragulaService.dropModel(this.TAG_SIDE_NAV).subscribe(({ targetModel }) => {
// const {target, source, targetModel, item} = params;
Expand Down Expand Up @@ -176,7 +158,6 @@ export class SideNavComponent implements OnDestroy {

ngOnDestroy(): void {
this._subs.unsubscribe();
this._dragulaService.destroy(this.PROJECTS_SIDE_NAV);
this._dragulaService.destroy(this.TAG_SIDE_NAV);
window.clearTimeout(this.keyboardFocusTimeout);
}
Expand All @@ -191,12 +172,6 @@ export class SideNavComponent implements OnDestroy {
return project.id;
}

getThemeColor(color: THEME_COLOR_MAP | string): { [key: string]: string } {
const standardColor = (THEME_COLOR_MAP as any)[color];
const colorToUse = standardColor ? standardColor : color;
return { background: colorToUse };
}

fetchProjectListState(): boolean {
return localStorage.getItem(LS.IS_PROJECT_LIST_EXPANDED) === 'true';
}
Expand Down Expand Up @@ -269,10 +244,6 @@ export class SideNavComponent implements OnDestroy {
}
}

openTimelineSettings(): void {
this._matDialog.open(DialogTimelineSetupComponent);
}

startTour(id: TourId): void {
this._shepherdService.show(id);
}
Expand All @@ -283,4 +254,26 @@ export class SideNavComponent implements OnDestroy {
}
return this._cachedIssueUrl;
}

dropOnProjectList(allItems: Project[], ev: CdkDragDrop<string, string, Project>): void {
if (ev.previousContainer === ev.container) {
const idsWithoutHidden = allItems
.filter((p) => !p.isHiddenFromMenu)
.map((p) => p.id);
const hiddenIds = allItems.filter((p) => p.isHiddenFromMenu).map((p) => p.id);
const hiddenLength = hiddenIds.length;
const project = ev.item.data;
// const targetProjectId = allIdsWithoutHidden[ev.currentIndex] as string;
const targetProjectId = idsWithoutHidden[ev.currentIndex - hiddenLength] as string;
console.log(targetProjectId);

if (targetProjectId) {
const newIds = [
...moveItemBeforeItem(idsWithoutHidden, project.id, targetProjectId),
...hiddenIds,
];
this.projectService.updateOrder(newIds);
}
}
}
}
7 changes: 7 additions & 0 deletions src/app/core-ui/side-nav/side-nav.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { RouterModule } from '@angular/router';
import { DragulaModule } from 'ng2-dragula';
import { WorkContextMenuModule } from '../work-context-menu/work-context-menu.module';
import { SideNavItemComponent } from './side-nav-item/side-nav-item.component';
import { CdkDrag, CdkDropList } from '@angular/cdk/drag-drop';
import { PlannerModule } from '../../features/planner/planner.module';
import { ScheduleEventComponent } from '../../features/schedule/schedule-event/schedule-event.component';

@NgModule({
imports: [
Expand All @@ -15,6 +18,10 @@ import { SideNavItemComponent } from './side-nav-item/side-nav-item.component';
DragulaModule,
WorkContextMenuModule,
SideNavItemComponent,
CdkDropList,
CdkDrag,
PlannerModule,
ScheduleEventComponent,
],
declarations: [SideNavComponent],
exports: [SideNavComponent],
Expand Down
2 changes: 1 addition & 1 deletion src/app/features/schedule/schedule/schedule.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@
(cdkDragMoved)="dragMoved($event)"
(cdkDragStarted)="dragStarted($event)"
(cdkDragReleased)="dragReleased($event)"
[cdkDragStartDelay]="IS_TOUCH_PRIMARY ? 75 : 0"
[cdkDragStartDelay]="IS_TOUCH_PRIMARY ? DRAG_DELAY_FOR_TOUCH : 0"
></schedule-event>
}
</div>
Expand Down
2 changes: 2 additions & 0 deletions src/app/features/schedule/schedule/schedule.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import { InlineMultilineInputComponent } from '../../../ui/inline-multiline-inpu
import { throttle } from 'helpful-decorators';
import { CreateTaskPlaceholderComponent } from '../create-task-placeholder/create-task-placeholder.component';
import { ShortcutService } from '../../../core-ui/shortcut/shortcut.service';
import { DRAG_DELAY_FOR_TOUCH } from '../../../app.constants';

// const DAYS_TO_SHOW = 5;
const D_HOURS = 24;
Expand Down Expand Up @@ -92,6 +93,7 @@ const IS_NOT_DRAGGING_CLASS = 'is-not-dragging';
export class ScheduleComponent implements AfterViewInit, OnDestroy {
FH = FH;
IS_TOUCH_PRIMARY = IS_TOUCH_PRIMARY;
DRAG_DELAY_FOR_TOUCH = DRAG_DELAY_FOR_TOUCH;
rowsByNr = Array.from({ length: D_HOURS * FH }, (_, index) => index).filter(
(v, index) => index % FH === 0,
);
Expand Down
6 changes: 2 additions & 4 deletions src/app/features/tag/store/tag.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ import {
upsertTag,
} from './tag.actions';
import { roundTsToMinutes } from '../../../util/round-ts-to-minutes';
import { moveItemInArray } from '../../../util/move-item-in-array';
import { PlannerActions } from '../../planner/store/planner.actions';
import { getWorklogStr } from '../../../util/get-work-log-str';
import { moveItemBeforeItem } from '../../../util/move-item-before-item';

export const TAG_FEATURE_NAME = 'tag';
const WORK_CONTEXT_TYPE: WorkContextType = WorkContextType.TAG;
Expand Down Expand Up @@ -551,13 +551,11 @@ export const tagReducer = createReducer<TagState>(

on(moveTaskInTagList, (state, { tagId, toTaskId, fromTaskId }) => {
const tagToUpdate = state.entities[tagId] as Tag;
const toIndex = tagToUpdate.taskIds.indexOf(toTaskId);
const fromIndex = tagToUpdate.taskIds.indexOf(fromTaskId);
return tagAdapter.updateOne(
{
id: tagId,
changes: {
taskIds: moveItemInArray(tagToUpdate.taskIds, fromIndex, toIndex),
taskIds: moveItemBeforeItem(tagToUpdate.taskIds, fromTaskId, toTaskId),
},
},
state,
Expand Down
7 changes: 7 additions & 0 deletions src/app/util/move-item-before-item.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { moveItemInArray } from './move-item-in-array';

export const moveItemBeforeItem = <T = string>(arr: T[], fromVal: T, toVal: T): T[] => {
const toIndex = arr.indexOf(toVal);
const fromIndex = arr.indexOf(fromVal);
return moveItemInArray(arr, fromIndex, toIndex);
};

0 comments on commit 3139a1f

Please sign in to comment.