@2bitgmbh/planning-component

[[TOC]]

Usage no npm install needed!

<script type="module">
  import 2bitgmbhPlanningComponent from 'https://cdn.skypack.dev/@2bitgmbh/planning-component';
</script>

README

Table of Content

[[TOC]]

Introduction

2PLAN is a Angular Component Library developed for Angular 11, which is used to manage different types of schedules. E.g. project plan, shift schedules and deployment plan. The library uses material design from Angular Material. It contains a planning component which can visualize the planning on project or resource basis and a calendar component where the resources can look up their schedules.

Getting Started

Installation

  1. To use this library you first need to install it with npm: npm install @2bitgmbh/planning-component.

  2. The library should now be in the node_modules folder of your project. Next, we just need to set up the translation before the library is fully functional. The translation in the library is implemented with ngx-translate and has its translation files in the following directory ./node_modules/@2Bitgmbh/planning-component/assets/i18n. These files are needed at runtime. To load the translations of the library, the angular.json of your project must be modified as follows:

    "architect": {
        "build": {
            "options": {
                "assets": [
                  {
                    "input": "node_modules/@2bitgmbh/planning-component/assets/i18n",
                    "glob": "*.json",
                    "output": "assets/i18n/planning-component"
                  }
                ]
            }
        }
    }
    
  3. After that, you need to use the LibraryTranslationService from 2PLAN and call this.libraryTranslationService.initTranslations(language); when the language is initialized in your project.

  4. The last step is to configure the locale for momentjs. Just add moment.locale(language); where your project language is initialized.

  5. The code to load the translation from the library could look like this.:

    this.translateService.use(language).subscribe(() => {
        moment.locale(language);
        this.dateAdapter.setLocale(language);
        this.libraryTranslationService.initTranslations(language);
    });
    

Version

Release Updates
0.2.0 Implemented Library for Angular 11

Build and Test

To build the library you have to be in the client directory of the workspace (./client) and it is required that the Angular CLI is installed. After that, you can enter the following command in the command line: ng build planning-component.

The library has no unit tests, but there are some E2E tests with Protractor in the directory ./client/e2e. The E2E tests can be run locally with the command npm run e2e-tests-local. Enter this command on the command line in the client directory of the workspace and the tests will be executed. In order for the tests to work, you also need to start the web application with ng serve and run the backend locally with Visual Studio. Make sure to run the web application on port 4200 and the backend on port 5000 or change the corresponding url of the web application and backend in the ./client/e2e/protractor.local.conf.js file.

Components

lib-gantt-activity

The lib-gantt-activity component is used to plan the activities of a project. With this component, allocations for activities can be created and edited. In addition, the activities can be edited directly.

If desired, menu items with additional functions can also be inserted via Content Projection.

Selector

lib-gantt-activity

Example

<lib-gantt-activity [activities$]="filteredActivitiesquot;
                    [allocations$]="allocationsquot;
                    [planningStartDate]="planningStartDate"
                    (editActivity)="editActivity($event)"
                    (addAllocationWithPreselectedData)="addAllocationWithPreselectedData($event)"
                    (editAllocation)="editAllocation($event)">
  <button mat-menu-item (click)="addActivity()">{{"ACTIVITY.CREATE" | translate}}</button>
</lib-gantt-activity>

GanttActivityComponent

Input

Name Required Type Default Description
activities$ true Observable<IActivityDto[]> undefined Activities which should be displayed as sections.
allocations$ true Observable<AllocationDto[]> undefined Allocations which should be displayed as items.
planningStartDate false Moment moment().startOf("day") The start time of the scheduler as a moment object.
lockPast false boolean false If the past is closed and only planning into the future should be allowed.

Output

Name Type Description
editActivity EventEmitter<string> Is called when an activity is clicked. The activity ID is returned.
addAllocationWithPreselectedData EventEmitter<{ sectionId: string, startDate: moment_.Moment }> Is called when an allocation with preselected data should be added. The activity ID (sectionId) and the start date for the allocation are passed.
editAllocation EventEmitter<string> Is called when an allocation is clicked. The allocation ID is passed.
saveAllocationAfterDragDrop EventEmitter<{ id: string, sectionId: string }> Is called when an allocation should be saved after drag and drop. Since the allocation can only be moved to another activity, only the allocation ID (id) and the new activity id (sectionId) are passed.

lib-gantt-resource

The lib-gantt-resource component is used for resource scheduling. With this component, allocations for resources can be created and edited. In addition, the resources can be edited directly.

If desired, menu items with additional functions can also be inserted via content projection.

Selector

lib-gantt-resource

Example

<lib-gantt-resource
  [resources$]="resourcesquot;
  [allocations$]="allocationsquot;
  [planningStartDate]="planningStartDate"
  (editResource)="editResource($event)"
  (addAllocationWithPreselectedData)="addAllocationWithPreselectedData($event)"
  (editAllocation)="editAllocation($event)">
</lib-gantt-resource>

GanttResoucreComponent

Input

Name Required Type Default Description
resources$ true Observable<IResourceDto[]> undefined Resources which should be displayed as sections.
allocations$ true Observable<AllocationDto[]> undefined Allocations which should be displayed as items.
planningStartDate false Moment moment().startOf("day") The start time of the scheduler as a moment object.
lockPast false boolean false If the past is closed and only planning into the future should be allowed.

Output

Name Type Description
editResource EventEmitter<string> Is called when a resource is clicked. The resource ID is passed.
addAllocationWithPreselectedData EventEmitter<{ sectionId: string, startDate: moment_.Moment }> Is called when an allocation with preselected data should be added. The resource ID (sectionId) and the start date for the allocation are passed.
editAllocation EventEmitter<string> Is called when an allocation is clicked. The allocation ID is passed.
saveAllocationAfterDragDrop EventEmitter<{ id: string, sectionId: string }> Is called when an allocation should be saved after drag and drop. Since the allocation can only be moved to another resource, only the allocation ID (id) and the new resource id (sectionId) are passed.

lib-gantt

Selector

lib-gantt [items] [sections]

Example

<lib-gantt [items]="items"
           [sections]="sections"
           [events]="events"
           [periodStart]="planningStartDate">
  <ng-content></ng-content>
</lib-gantt>

Input

Name Required Type Default Description
items true Item[] null An array of Item to fill up the items of the scheduler.
sections true Section[] null An array of Section to fill up the sections of the scheduler.
events false Events new Events() The events that can be hooked into.
periodStart false Moment moment().startOf("day") The start time of the scheduler as a moment object.
lockPast false boolean false If the past is closed and only planning into the future should be allowed.
locale false string "" Defines which locale for Moment.js should be loaded. By default, Moment.js uses English (United States) locale strings.
showBusinessDayOnly false boolean false Whether only working days are displayed (Mon-Fri).

Models

Section

Sections are displayed on the left side of the scheduler.

Name Required Type Default Description
id true string null A unique identifier for the section (e.q. activity or resource id).
name true string null The name to display for the section.
tooltip false string null It is used to display tooltip for the section.
absences false IAbsenceDto[] | undefined undefined The absences for a section. It is used to display absences in the schedule. This property is useful for resource planning
hasConflicts false boolean false Whenever a conflict has arisen in the planning for the section. If it is true a red bar is displayed.

Item

Items are used to display the assignments of a section.

Name Required Type Default Description
id true number null The identifier for the allocation.
name true string null The name to display for the item.
start true any null A Moment object denoting where this object starts.
end true any null A Moment object denoting where this object ends.
sectionID true number null The id of the section that this item belongs to.
tooltip false string null It is used to display tooltip for the section.
color false string "#ffce00" The background color for the allocation. This is useful to visualize the affiliation to a project.
hasConflicts false boolean false Whenever a conflict for this allocation exists. If it is true, the background color will be red.

Events

The events are executed on interactions with the items / sections and can be used to react to them.

Name Parameters Return type Description
SectionClickEvent section: Section void Triggered when a section is clicked.
SectionContextMenuEvent section: Section, event: MouseEvent void Triggered when a section is righted click.
PeriodChange start: moment.Moment, end: moment.Moment void Triggered when the period is changed.
AddAllocationWithPreselectedData sectionId: string, startDate: moment.Moment void Triggered when a cell in the scheduler is clicked.
EditAllocation id: string void Triggered when an item is clicked.
SaveAllocationAfterDragDrop id: string, sectionId: string void Triggered when an item is dropped to a new section. id is the id of the item and sectionId is the id of the target section.

lib-calendar

The lib-calendar is used to display a calendar with monthly and weekly view. The calendar is filled with allocations on the corresponding date spans.

Selector

lib-calendar

Example

<lib-calendar 
    [events]="events" 
    [monthViewSelected]="true"
    (openAllocation)="openAllocation($event)">
</lib-calendar>

Inputs

Name Required Type Default Description
events true IAllocationDto[] null Allocations which are displayed in the calendar.
monthViewSelected false boolean true Sets the initial displayed calendar view. If true the month view is displayed otherwise the week view is displayed.

Outputs

Name Type Description
openAllocation EventEmitter<string> Is called when an allocation is clicked. The allocation ID is passed.

lib-calendar-month

The lib-calendar-month displays a calendar monthly view. The calendar is filled with allocations on the corresponding time period. If desired, a navigation in the selection header can be added via content projection.

Example

<lib-calendar-month 
    *ngIf="monthViewSelected"
    [events]="events"
    [(startDate)]="currentDate"
    (openAllocation)="openAllocationHandler($event)">
  <ng-container>
    <button mat-icon-button [matMenuTriggerFor]="dropMenu">
      <mat-icon>more_vert</mat-icon>
    </button>
    <mat-menu #dropMenu="matMenu">
      <button mat-menu-item
              (click)="changeView('month')"
              [class.selected-view]="monthViewSelected">
        {{ "CALENDAR.MONTH" | translate }}
      </button>
      <button mat-menu-item
              (click)="changeView('week')"
              [class.selected-view]="!monthViewSelected">
        {{ "CALENDAR.WEEK" | translate }}
      </button>
    </mat-menu>
  </ng-container>
</lib-calendar-month>

Calendar Month

Inputs

Name Required Type Default Description
events true IAllocationDto[] null Allocations which are displayed in the calendar.
startDate true Date new Date() The calendar initially displays the month of the date passed starting with the previous Monday of the first day in that month.

Outputs

Name Type Description
startDateChange EventEmitter<Date> Is called when the month has been changed. The start date of the new month is passed.
openAllocation EventEmitter<string> Is called when an allocation is clicked. The allocation ID is passed.

lib-calendar-week

The lib-calendar-week displays a calendar weekly view. The calendar is filled with allocations on the corresponding time period. If desired, a navigation in the selection header can be added via content projection.

Example

<lib-calendar-week 
    [events]="events"
    [(startDate)]="currentDate"
    (openAllocation)="openAllocationHandler($event)">
  <ng-container>
    <button mat-icon-button [matMenuTriggerFor]="dropMenu">
      <mat-icon>more_vert</mat-icon>
    </button>
    <mat-menu #dropMenu="matMenu">
      <button mat-menu-item
              (click)="changeView('month')"
              [class.selected-view]="monthViewSelected">
        {{ "CALENDAR.MONTH" | translate }}
      </button>
      <button mat-menu-item
              (click)="changeView('week')"
              [class.selected-view]="!monthViewSelected">
        {{ "CALENDAR.WEEK" | translate }}
      </button>
    </mat-menu>
  </ng-container>
</lib-calendar-week>

Calendar Week

Inputs

Name Required Type Default Description
events true IAllocationDto[] null Allocations which are displayed in the calendar.
startDate true Date new Date() The calendar initially displays the week of the date passed. Starting at the previous Monday.

Outputs

Name Type Description
startDateChange EventEmitter<Date> Is called when the week has been changed. The start date of the new week is passed.
openAllocation EventEmitter<string> Is called when an allocation is clicked. The allocation ID is passed.

lib-message-overview

The lib-message-overview component displays an overview of all messages. They can be filtered by the names of the concerning projects, activities or resources. Furthermore, it provides a filter for the message type and for showing or hiding the accepted messages.

Example

<lib-message-overview 
    [messages]="data.messages" 
    (acceptMessageEvent)="handleAcceptEvent($event)" 
    (solveConflictEvent)="handleSolveConflictEvent($event)">
</lib-message-overview>

Calendar Month

Inputs

Name Required Type Default Description
messages true IMessageDto[] null Messages that should be displayed in the overview.
messageType false number undefined Preset for the message type filter.

Outputs

Name Type Description
acceptMessageEvent EventEmitter<string> Returns the message ID of the message that the user clicked to accept.
solveConflictEvent EventEmitter<IMessageDto> Returns the message that the user wants to solve.

lib-datetime

The lib-gantt-resource component can be used if a user should be able to to enter a date and time. If the times are not relevant, the switch "all day" can be activated.

The component ensures that the start must be before the end. In addition, further validations can be defined as input parameters (see startDateValidator and endDateValidator).

Selector

lib-datetime [formGroup] [start] [end]

Example

<lib-datetime [formGroup]="activityForm"
              [startParent]="activityProject.startDate"
              [endParent]="activityProject.endDate"
              [start]="activity.startDate"
              [end]="activity.endDate"
              [disabled]="!isEditable"
              [startDateValidator]="isStartDateValid"
              [endDateValidator]="isEndDateValid">
</lib-datetime>

DateTime

Input

Name Required Type Default Description
formGroup true FormGroup null The form group from the outer form element into which the component is integrated. For the input fields, form controls are added to the form group.
start true Date null The start date to be displayed in the input field.
end true Date null The end date to be displayed in the input field.
startParent false Date | undefined null The start date of the parent object. For example, an allocation must be within the date range of an activity. So the start date of the activity is passed here. The passed date is set as min property in the datepicker. Furthermore the date is set as start date if start is undefined.
endParent false Date | undefined null The end date of the parent object. For example, an allocation must be within the date range of an activity. So the end date of the activity is passed here. The passed date is set as max property in the datepicker. Furthermore the date is set as start date if end is undefined.
startDateValidator false (selectedStart: moment_.Moment) => any null startDateValidator is executed when the start date changes. If there is no error the function should return undefined. Otherwise the function should return an object with a form error (e.g. {dateRangeProject: true}). The form error is needed to display an error message below the input field.
endDateValidator false (selectedEnd: moment_.Moment) => any null endDateValidator is executed when the end date changes. If there is no error the function should return undefined. Otherwise the function should return an object with a form error (e.g. {dateRangeProject: true}). The form error is needed to display an error message below the input field.
disabled false boolean false Whether all fields should be disabled.

NOTE formGroup: The form controls are added to the form group with the following keys:

  • "startDate"
  • "startTime"
  • "endDate"
  • "endTime"

StartDate and endDate contains a Moment.js object which combines the entered date and time.

lib-allocation-dialog

The lib-allocation-dialog component can be used to create or edit an allocation via dialog. It should be used in project and resource planning when an allocation is to be created or edited.

Selector

lib-allocation-dialog

Example

const dialogRef = this.dialog.open(AllocationDialogComponent, {
    width: "80%",
    data: {
        allocation,
        currentProjectId,
        projects$,
        projectActivities$,
        resources$: this.resourcesClient.getResources(),
        loadActivitiesForProjectFunction: this.loadActivitiesForProject,
        lockPast$,
        messages,
    },
});

AllocationDialog

Material Dialog Data

Name Type Description
allocation IAllocationDto The dto of the allocation to be displayed. If a new allocation is to be created, create a new dto.
projects$ Observable<IProjectDto[]> | undefined The projects which can be selected in the dialog. if undefined is passed, the project of an allocation cannot be changed.
currentProjectId string | undefined The project ID to which the allocation activity belongs to. The value should only be specified if projects$ is not undefined. Otherwise, undefined can be passed.
projectActivities$ Observable<IActivityDto[]> | undefined All activities of the currently active project or undefined if project is not specified yet.
resources$ Observable<IResourceDto[]> All resources which are available for selection for the event.
loadActivitiesForProjectFunction (projectId: string) => Observable<IActivityDto[]> Function which is called when the project changes. The function should return all activities of the newly selected project.
lockPast$ Observable<boolean> | undefined Whether the past is closed and only planning into the future is allowed.
messages IMessageDto[] All messages which belong to the allocation or an empty array if no messages exists.

Public Members

Name Type Default Description
acceptMessageEvent EventEmitter<string> new EventEmitter<string>() Is called when a message is accepted. The message ID is passed.
You have to subscribe to this event and forward the call to the server to save the message.
solveConflictEvent EventEmitter<IMessageDto> new EventEmitter<IMessageDto>() Is called when a message is to be resolved.
You have to subscribe to this event and navigate to the route where the planner can solve the message.

Example

const dialogRef = this.dialog.open(AllocationDialogComponent, { ... });
const messageAcceptSubscription = dialogRef.componentInstance.acceptMessageEvent.subscribe(value => {
    this.handleMessageAcceptEvent(value, dialogRef, allocation.id);
});
const solveConflictEvent = dialogRef.componentInstance.solveConflictEvent.subscribe(value => {
    this.handleSolveConflictEvent(value);
});
dialogRef.afterClosed().subscribe(result => {
      messageAcceptSubscription.unsubscribe();
    solveConflictEvent.unsubscribe();
});

Dialog result

On Save:

{ event: "save", data: IAllocationDto }

On Cancel:

{ event: "cancel" }

On Delete

{event: "delete", data: IAllocationDto }

lib-allocation-calendar-dialog

The lib-allocation-calendar-dialog component can be used if details of an allocation from the calendar are to be displayed. The allocation is not editable in this dialog. Only the work can be set to done if this has been activated on the activity of the allocation.

Selector

lib-allocation-calendar-dialog

Example

const dialogRef = this.dialog.open(AllocationCalendarDialogComponent, {
    width: "80%",
    data: {
        allocation: dto,
        isAcknowledgementActive: activityDto.acknowledgement,
    },
});

AllocationCalendarDialog

Material Dialog Data

Name Type Description
allocation IAllocationDto The dto of the allocation to be displayed.
isAcknowledgementActive boolean Whether acknowledgment is active on the activity of the allocation. If true the allocation can be marked as done.

Dialog result

On Save:

{ event: "save", data: IAllocationDto }

On Cancel:

{ event: "cancel" }

View Models

The following class diagram describes the view models and their connections. The properties that are used in the library are highlighted.

ViewModels

IAllocationDto

The IAllocationDto is the most important class, which is needed in almost all components. When a resource is assigned to an operation to process it, a corresponding allocation is created. The IAllocationDto is needed to display an allocation in the gantt or in the calendar or to display the exact details of an allocation in the dialog.

Name Type Description
resourceId string The id of the resource to which the allocation was assigned.
activityId string The id of the activity to which the allocation was assigned.
resourceName string | undefined Is used to display the name of the assigned resource of an allocation in lib-gantt-activity.
activityName string | undefined Is used to display the name of the assigned activity of an allocation.
activityProjectName string | undefined Is used to display in lib-allocation-calendar-dialog the name of the project to which the activity belongs.
activityProjectColour string | undefined The project color is used to highlight the allocation.
workingHours number The number of hours a resource has available to complete the work.
isAcknowledged boolean | undefined Whenever the resource has completed the activity.
messages MessageTypes | undefined This property is used to find out if there exists messages for an allocation. If so, the allocation is marked red in lib-gantt.

IActivityDto

For each project, several activities can be defined. The IActivityDto is used to perform the planning and to create IAllocationDto.

Name Type Description
startDate Date | undefined When an allocation is created / edited, the start date of the activity is used to check if the allocation has the same or a greater start date. Otherwise the allocation cannot be saved.
endDate Date | undefined When an allocation is created / edited, the end date of the activity is used to check if the allocation has the same or a smaller end date. Otherwise the allocation cannot be saved.
skills ISkillDto | undefined Is used to calculate whether the skills of the activity of an allocation match the skills of a resource to determine if the resource is appropriate for the allocation.
messages MessageTypes | undefined This property is used to find out if there exists messages for an activity. If so, the activity is marked red in lib-gantt.

IResourceDto

The IResourceDto is used to assign an allocation to a resource.

Name Type Description
skills ISkillDto | undefined Is used to calculate whether the skills of a resource match the skills of the activity of an allocation to determine if the resource is appropriate for the allocation.
workingDays IWorkingDayDto[] | undefined Is used to calculate whether the days between the start and end dates of an allocation are working days of the resource to determine if the resource is appropriate for the allocation.
absences IAbsenceDto[] | undefined Is used to calculate if the resource has absences between the days from the start and end dates of an allocation to determine if the resource is appropriate for the allocation.

IMessageDto

Messages are created, when errors occur during planning. These messages are displayed and can be accepted or resolved.

Name Type Description
startDate Date | undefined Defines the start date of a conflict. Only used for the validation cases ResourceNotAvailable, ResourceMultipleBooking, HolidayBooking.
endDate Date | undefined Defines the end date of a conflict. Only used for the validation cases ResourceNotAvailable, ResourceMultipleBooking, HolidayBooking.
validationCase ValidationCase Defines why a message exists. Based on the case, an appropriate message is displayed.
projectName string | undefined Is only used if the message affects only the project. The project name is displayed in the message details.
activityName string | undefined Is only used if the message affects only the activity of a project. The activity name is displayed in the message details.
allocations MessageAllocationSummaryDto[] | undefined Defines which allocations are affected by the message. E.g. if there are parallel bookings for a resource on different projects, only one message will be created and the affected allocations will be listed in allocations. In MessageAllocationSummaryDto the information is stored, which project, which activity and which resource the message concerns.