Hide user field in my page spent time

pull/10996/head
Oliver Günther 2 years ago
parent 3a5645b74c
commit f299508050
No known key found for this signature in database
GPG Key ID: A3A8BDAD7C0C552C
  1. 4
      frontend/src/app/features/calendar/te-calendar/te-calendar.component.ts
  2. 5
      frontend/src/app/features/hal/resources/time-entry-resource.ts
  3. 2
      frontend/src/app/shared/components/fields/display/field-types/wp-spent-time-display-field.module.ts
  4. 2
      frontend/src/app/shared/components/op-context-menu/wp-context-menu/wp-single-context-menu.ts
  5. 36
      frontend/src/app/shared/components/time_entries/create/create.service.ts
  6. 21
      frontend/src/app/shared/components/time_entries/edit/edit.service.ts
  7. 48
      frontend/src/app/shared/components/time_entries/form/form.component.html
  8. 2
      frontend/src/app/shared/components/time_entries/form/form.component.ts
  9. 1
      frontend/src/app/shared/components/time_entries/shared/modal/base.modal.html
  10. 33
      frontend/src/app/shared/components/time_entries/shared/modal/base.modal.ts
  11. 2
      modules/my_page/spec/features/my/time_entries_current_user_spec.rb
  12. 2
      spec/features/support/components/time_logging_modal.rb

@ -372,7 +372,7 @@ export class TimeEntryCalendarComponent {
private editEvent(entry:TimeEntryResource):void {
this
.timeEntryEdit
.edit(entry)
.edit(entry, { showUserField: false })
.then((modificationAction) => {
this.updateEventSet(modificationAction.entry, modificationAction.action);
})
@ -418,7 +418,7 @@ export class TimeEntryCalendarComponent {
this
.timeEntryCreate
.create(date)
.create(date, undefined, { showUserField: false })
.then((modificationAction) => {
this.updateEventSet(modificationAction.entry, modificationAction.action);
})

@ -28,6 +28,7 @@
import { HalResource } from 'core-app/features/hal/resources/hal-resource';
import { ProjectResource } from 'core-app/features/hal/resources/project-resource';
import { InputState } from 'reactivestates';
import Formattable = api.v3.Formattable;
export class TimeEntryResource extends HalResource {
@ -37,8 +38,8 @@ export class TimeEntryResource extends HalResource {
comment:Formattable;
public get state() {
return this.states.timeEntries.get(this.id!) as any;
public get state():InputState<this> {
return this.states.timeEntries.get(this.id as string) as unknown as InputState<this>;
}
/**

@ -100,7 +100,7 @@ export class WorkPackageSpentTimeDisplayField extends EstimatedTimeDisplayField
private showTimelogWidget(wp:WorkPackageResource) {
this.timeEntryCreateService
.create(moment(new Date()), wp, false)
.create(moment(new Date()), wp, { showWorkPackageField: false })
.catch(() => {
// do nothing, the user closed without changes
});

@ -65,7 +65,7 @@ export class WorkPackageSingleContextMenuDirective extends OpContextMenuTrigger
break;
case 'log_time':
this.timeEntryCreateService
.create(moment(new Date()), this.workPackage, false)
.create(moment(new Date()), this.workPackage, { showWorkPackageField: false })
.catch(() => {
// do nothing, the user closed without changes
});

@ -1,4 +1,7 @@
import { Injectable, Injector } from '@angular/core';
import {
Injectable,
Injector,
} from '@angular/core';
import { OpModalService } from 'core-app/shared/components/modal/modal.service';
import { HalResourceService } from 'core-app/features/hal/services/hal-resource.service';
import { I18nService } from 'core-app/core/i18n/i18n.service';
@ -12,6 +15,8 @@ import { WorkPackageResource } from 'core-app/features/hal/resources/work-packag
import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service';
import { SchemaCacheService } from 'core-app/core/schemas/schema-cache.service';
import { TimeEntryResource } from 'core-app/features/hal/resources/time-entry-resource';
import { TimeEntryModalOptions } from 'core-app/shared/components/time_entries/edit/edit.service';
import { HalResource } from 'core-app/features/hal/resources/hal-resource';
@Injectable()
export class TimeEntryCreateService {
@ -24,12 +29,20 @@ export class TimeEntryCreateService {
readonly i18n:I18nService) {
}
public create(date:Moment, wp?:WorkPackageResource, showWorkPackageField = true) {
public create(
date:Moment,
wp?:WorkPackageResource,
options:TimeEntryModalOptions = {},
):Promise<{ entry:TimeEntryResource, action:'create' }> {
return new Promise<{ entry:TimeEntryResource, action:'create' }>((resolve, reject) => {
this
void this
.createNewTimeEntry(date, wp)
.then((changeset) => {
const modal = this.opModalService.show(TimeEntryCreateModalComponent, this.injector, { changeset, showWorkPackageField });
const modal = this.opModalService.show(
TimeEntryCreateModalComponent,
this.injector,
{ ...options, changeset },
);
modal
.closingEvent
@ -45,12 +58,13 @@ export class TimeEntryCreateService {
});
}
public createNewTimeEntry(date:Moment, wp?:WorkPackageResource) {
public createNewTimeEntry(date:Moment, wp?:WorkPackageResource):Promise<ResourceChangeset> {
const payload:any = {
spentOn: date.format('YYYY-MM-DD'),
};
if (wp) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
payload._links = {
workPackage: {
href: wp.href,
@ -73,9 +87,13 @@ export class TimeEntryCreateService {
return this.halEditing.edit<TimeEntryResource, ResourceChangeset<TimeEntryResource>>(entry, form);
}
private initializeNewResource(form:FormResource) {
const entry = this.halResource.createHalResourceOfType<TimeEntryResource>('TimeEntry', form.payload.$plain());
private initializeNewResource(form:FormResource):TimeEntryResource {
const entry = this.halResource.createHalResourceOfType<TimeEntryResource>(
'TimeEntry',
(form.payload as HalResource).$plain(),
);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
entry.$links.schema = { href: 'new' };
entry._type = 'TimeEntry';
@ -83,9 +101,11 @@ export class TimeEntryCreateService {
entry.hours = 'PT1H';
// Set update link to form
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,no-multi-assign
entry.update = entry.$links.update = form.$links.self;
// Use POST /work_packages for saving link
entry.updateImmediately = entry.$links.updateImmediately = (payload:{}) => this
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,no-multi-assign
entry.updateImmediately = entry.$links.updateImmediately = (payload:Record<string, unknown>) => this
.apiV3Service
.time_entries
.post(payload)

@ -9,6 +9,11 @@ import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service';
import { TimeEntryResource } from 'core-app/features/hal/resources/time-entry-resource';
import { TimeEntryEditModalComponent } from './edit.modal';
export interface TimeEntryModalOptions {
showWorkPackageField?:boolean;
showUserField?:boolean;
}
@Injectable()
export class TimeEntryEditService {
constructor(readonly opModalService:OpModalService,
@ -19,18 +24,26 @@ export class TimeEntryEditService {
readonly i18n:I18nService) {
}
public edit(entry:TimeEntryResource) {
public edit(
entry:TimeEntryResource,
options:TimeEntryModalOptions = {},
):Promise<{ entry:TimeEntryResource, action:'update'|'destroy' }> {
return new Promise<{ entry:TimeEntryResource, action:'update'|'destroy' }>((resolve, reject) => {
this
void this
.createChangeset(entry)
.then((changeset) => {
const modal = this.opModalService.show(TimeEntryEditModalComponent, this.injector, { changeset });
const modal = this.opModalService.show(
TimeEntryEditModalComponent,
this.injector,
{ ...options, changeset },
);
modal
.closingEvent
.pipe(take(1))
.subscribe(() => {
if (modal.destroyedEntry) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
modal.destroyedEntry.delete().then(() => {
resolve({ entry: modal.destroyedEntry, action: 'destroy' });
});
@ -44,7 +57,7 @@ export class TimeEntryEditService {
});
}
public createChangeset(entry:TimeEntryResource) {
public createChangeset(entry:TimeEntryResource):Promise<ResourceChangeset<TimeEntryResource>> {
return this
.apiV3Service
.time_entries

@ -4,20 +4,22 @@
[inEditMode]="inEditMode"
(onSaved)="signalModifiedEntry($event)">
<div class="attributes-map">
<div class="attributes-map--key"
[ngClass]="{'-required': isRequired('user')}"
[textContent]="schema.user.name">
</div>
<div class="attributes-map--value">
<editable-attribute-field [resource]="entry"
[wrapperClasses]="'-tiny'"
[fieldName]="'user'">
</editable-attribute-field>
</div>
<ng-container *ngIf="showUserField">
<div class="attributes-map--key"
[ngClass]="{'-required': isRequired('user')}"
[textContent]="schema.user.name">
</div>
<div class="attributes-map--value">
<editable-attribute-field [resource]="entry"
[wrapperClasses]="'-tiny'"
[fieldName]="'user'">
</editable-attribute-field>
</div>
</ng-container>
<div class="attributes-map--key"
[ngClass]="{'-required': isRequired('spentOn')}"
[textContent]="schema.spentOn.name">
[ngClass]="{'-required': isRequired('spentOn')}"
[textContent]="schema.spentOn.name">
</div>
<div class="attributes-map--value">
<editable-attribute-field [resource]="entry"
@ -37,17 +39,17 @@
</editable-attribute-field>
</div>
<div *ngIf="showWorkPackageField"
class="attributes-map--key"
[ngClass]="{'-required': isRequired('workPackage')}"
[textContent]="schema.workPackage.name">
</div>
<div *ngIf="showWorkPackageField"
class="attributes-map--value">
<editable-attribute-field [resource]="entry"
[fieldName]="'workPackage'">
</editable-attribute-field>
</div>
<ng-container *ngIf="showWorkPackageField">
<div lass="attributes-map--key"
[ngClass]="{'-required': isRequired('workPackage')}"
[textContent]="schema.workPackage.name">
</div>
<div class="attributes-map--value">
<editable-attribute-field [resource]="entry"
[fieldName]="'workPackage'">
</editable-attribute-field>
</div>
</ng-container>
<div class="attributes-map--key"
[ngClass]="{'-required': isRequired('activity')}"

@ -30,6 +30,8 @@ export class TimeEntryFormComponent extends UntilDestroyedMixin implements OnIni
@Input() showWorkPackageField = true;
@Input() showUserField = true;
@Output() modifiedEntry = new EventEmitter<{ savedResource:TimeEntryResource, isInital:boolean }>();
@ViewChild('editForm', { static: true }) editForm:EditFormComponent;

@ -12,6 +12,7 @@
<te-form #editForm
[changeset]="changeset"
[showWorkPackageField]="showWorkPackageField"
[showUserField]="showUserField"
(modifiedEntry)="setModifiedEntry($event)">
</te-form>
</div>

@ -1,5 +1,10 @@
import {
ChangeDetectorRef, Directive, ElementRef, Inject, Injector, ViewChild,
ChangeDetectorRef,
Directive,
ElementRef,
Inject,
Injector,
ViewChild,
} from '@angular/core';
import { OpModalComponent } from 'core-app/shared/components/modal/modal.component';
import { OpModalLocalsToken } from 'core-app/shared/components/modal/modal.service';
@ -9,6 +14,8 @@ import { TimeEntryFormComponent } from 'core-app/shared/components/time_entries/
import { HalResource } from 'core-app/features/hal/resources/hal-resource';
import { InjectField } from 'core-app/shared/helpers/angular/inject-field.decorator';
import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service';
import { TimeEntryResource } from 'core-app/features/hal/resources/time-entry-resource';
import { ResourceChangeset } from 'core-app/shared/components/fields/changeset/resource-changeset';
@Directive()
export abstract class TimeEntryBaseModal extends OpModalComponent {
@ -40,19 +47,23 @@ export abstract class TimeEntryBaseModal extends OpModalComponent {
public abstract setModifiedEntry($event:{ savedResource:HalResource, isInital:boolean }):void;
public get changeset() {
public get changeset():ResourceChangeset<TimeEntryResource> {
return this.locals.changeset;
}
public get entry() {
public get entry():TimeEntryResource {
return this.changeset.projectedResource;
}
public get showWorkPackageField() {
return this.locals.showWorkPackageField !== undefined ? this.locals.showWorkPackageField : true;
public get showWorkPackageField():boolean {
return this.locals.showWorkPackageField !== false;
}
public saveEntry() {
public get showUserField():boolean {
return this.locals.showUserField !== false;
}
public saveEntry():void {
this.formInFlight = true;
this.editForm.save()
@ -63,22 +74,22 @@ export abstract class TimeEntryBaseModal extends OpModalComponent {
});
}
public get saveText() {
public get saveText():string {
return this.i18n.t('js.button_save');
}
public get saveAllowed() {
public get saveAllowed():boolean {
return true;
}
public get deleteAllowed() {
public get deleteAllowed():boolean {
return true;
}
protected reloadWorkPackageAndClose() {
protected reloadWorkPackageAndClose():void {
// reload workPackage
if (this.entry.workPackage) {
this
void this
.apiV3Service
.work_packages
.id(this.entry.workPackage)

@ -184,6 +184,8 @@ describe 'My page time entries current user widget spec', type: :feature, js: tr
time_logging_modal.has_field_with_value 'spentOn', (Date.today.beginning_of_week(:sunday) + 3.days).strftime
time_logging_modal.shows_field 'user', false
expect(page)
.not_to have_selector('.ng-spinner-loader')

@ -114,6 +114,8 @@ module Components
'wp-new-inline-edit--field-spentOn'
when 'work_package'
'wp-new-inline-edit--field-workPackage'
when 'user'
'wp-new-inline-edit--field-user'
end
end

Loading…
Cancel
Save