Add requirements list and editing, fix type issues
Added suport for numbers and dates
This commit is contained in:
parent
744cc29346
commit
ee4fee004d
11 changed files with 107 additions and 32 deletions
|
@ -15,13 +15,13 @@ export class FulfillmentModeList implements ListResponse<FulfillmentMode> {
|
|||
export class FulfillmentModeCreateInput implements Omit<DataObject<FulfillmentMode>, 'requirements' | 'courseId'> {
|
||||
@field()
|
||||
name: string;
|
||||
@field()
|
||||
@field(returns => Int)
|
||||
threshold2: number;
|
||||
@field()
|
||||
@field(returns => Int)
|
||||
threshold3: number;
|
||||
@field()
|
||||
@field(returns => Int)
|
||||
threshold4: number;
|
||||
@field()
|
||||
@field(returns => Int)
|
||||
threshold5: number;
|
||||
@field(returns => ID)
|
||||
courseId: number;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ListResponse } from './list';
|
||||
import { Requirement } from '../models';
|
||||
import { field, inputType, Int, objectType } from '@loopback/graphql';
|
||||
import { field, ID, inputType, Int, objectType } from '@loopback/graphql';
|
||||
import { DataObject } from '@loopback/repository';
|
||||
|
||||
@objectType()
|
||||
|
@ -12,21 +12,24 @@ export class RequirementList implements ListResponse<Requirement> {
|
|||
}
|
||||
|
||||
@inputType()
|
||||
export class RequirementCreateInput implements Pick<DataObject<Requirement>, 'name' | 'description' | 'deadline' | 'minPoints' | 'maxPoints'> {
|
||||
export class RequirementCreateInput implements Pick<DataObject<Requirement>, 'name' | 'description' | 'deadline' | 'minPoints' | 'maxPoints' | 'fulfillmentModeId'> {
|
||||
@field()
|
||||
deadline: Date;
|
||||
@field()
|
||||
name: string;
|
||||
@field()
|
||||
description: string;
|
||||
@field()
|
||||
@field(returns => Int)
|
||||
minPoints: number;
|
||||
@field()
|
||||
@field(returns => Int)
|
||||
maxPoints: number;
|
||||
@field(returns => ID)
|
||||
fulfillmentModeId: number;
|
||||
|
||||
}
|
||||
|
||||
@inputType()
|
||||
export class RequirementUpdateInput extends RequirementCreateInput {
|
||||
@field(returns => Int)
|
||||
@field(returns => ID)
|
||||
id: number;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Entity, hasMany, model, property } from '@loopback/repository';
|
||||
import { Requirement } from './requirement.model';
|
||||
import { field, ID, objectType } from '@loopback/graphql';
|
||||
import { field, ID, Int, objectType } from '@loopback/graphql';
|
||||
|
||||
@model()
|
||||
@objectType()
|
||||
|
@ -24,28 +24,28 @@ export class FulfillmentMode extends Entity {
|
|||
type: 'number',
|
||||
required: true,
|
||||
})
|
||||
@field()
|
||||
@field(returns => Int)
|
||||
threshold2: number;
|
||||
|
||||
@property({
|
||||
type: 'number',
|
||||
required: true,
|
||||
})
|
||||
@field()
|
||||
@field(returns => Int)
|
||||
threshold3: number;
|
||||
|
||||
@property({
|
||||
type: 'number',
|
||||
required: true,
|
||||
})
|
||||
@field()
|
||||
@field(returns => Int)
|
||||
threshold4: number;
|
||||
|
||||
@property({
|
||||
type: 'number',
|
||||
required: true,
|
||||
})
|
||||
@field()
|
||||
@field(returns => Int)
|
||||
threshold5: number;
|
||||
|
||||
@property({
|
||||
|
|
|
@ -2,10 +2,20 @@
|
|||
<form [formGroup]="formGroup">
|
||||
<div *ngFor="let field of fields">
|
||||
<mat-label>{{ field.title }}</mat-label>
|
||||
<span [ngSwitch]="getType(item[field.name])">
|
||||
<span [ngSwitch]="getType(field, item[field.name])">
|
||||
<span *ngSwitchCase="'boolean'">
|
||||
<mat-checkbox [checked]="item[field.name]" [formControlName]="field.name"></mat-checkbox>
|
||||
</span>
|
||||
<span *ngSwitchCase="'integer'">
|
||||
<mat-form-field>
|
||||
<input matInput [formControlName]="field.name" type="number" [value]="item[field.name]"/>
|
||||
</mat-form-field>
|
||||
</span>
|
||||
<span *ngSwitchCase="'date'">
|
||||
<mat-form-field>
|
||||
<mat-datepicker [formControlName]="field.name" [ngModel]="item[field.name]"></mat-datepicker>
|
||||
</mat-form-field>
|
||||
</span>
|
||||
<mat-form-field *ngSwitchDefault>
|
||||
<input matInput [formControlName]="field.name" type="text" [value]="item[field.name]"/>
|
||||
</mat-form-field>
|
||||
|
|
|
@ -15,13 +15,13 @@ export class EditComponent<T extends HasID, QT extends QueryResult<T>, UT extend
|
|||
implements OnInit {
|
||||
|
||||
item?: T;
|
||||
creating = false;
|
||||
@Input() creating = false;
|
||||
isLoading = true;
|
||||
|
||||
@Input() gql: Query<QT, HasID>;
|
||||
@Input() updateMutation: Mutation<UT, MutationInput<MIU, T>>;
|
||||
@Input() createMutation: Mutation<CT, MutationInput<MIC, T>>;
|
||||
@Input() fields: { title: string, name: keyof T, readonly?: (item: T) => boolean }[];
|
||||
@Input() fields: { title: string, name: keyof T, readonly?: (item: T) => boolean, type?: string }[];
|
||||
@Input() itemType: T;
|
||||
/**
|
||||
* Beküldés előtt extra adat hozzáadása
|
||||
|
@ -42,7 +42,7 @@ export class EditComponent<T extends HasID, QT extends QueryResult<T>, UT extend
|
|||
const url = this.route.snapshot.url;
|
||||
this.item = this.customItem;
|
||||
this.id = this.item?.id ?? this.gql ? url[url.length - 1].path : 'new';
|
||||
if (!this.item && this.id !== 'new' && this.gql) {
|
||||
if (!this.item && this.id !== 'new' && this.gql && !this.creating) {
|
||||
const data = (await this.gql.fetch({id: this.id}).toPromise()).data;
|
||||
this.key = Object.keys(data).filter(k => k !== '__typename')[0];
|
||||
this.item = data[this.key];
|
||||
|
@ -87,8 +87,8 @@ export class EditComponent<T extends HasID, QT extends QueryResult<T>, UT extend
|
|||
await this.router.navigate(['..'], {relativeTo: this.route});
|
||||
}
|
||||
|
||||
getType(itemElement: any): typeof itemElement {
|
||||
return typeof itemElement;
|
||||
getType(field: typeof EditComponent.prototype.fields[number] | null, value: any): typeof value | string {
|
||||
return field?.type ?? typeof value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import { ReactiveFormsModule } from '@angular/forms';
|
|||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
|
||||
|
||||
@NgModule({
|
||||
|
@ -33,7 +34,8 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
|||
ReactiveFormsModule,
|
||||
MatInputModule,
|
||||
MatCheckboxModule,
|
||||
MatTooltipModule
|
||||
MatTooltipModule,
|
||||
MatDatepickerModule
|
||||
]
|
||||
})
|
||||
export class SharedComponentsModule {
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
<ng-container *ngFor="let col of columns" [matColumnDef]="col.prop">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ col.title }}</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<span [ngSwitch]="getType(item[col.prop])">
|
||||
<span [ngSwitch]="getType(col, item[col.prop])">
|
||||
<span *ngSwitchCase="'boolean'"><mat-checkbox [checked]="item[col.prop]" disabled="disabled"></mat-checkbox></span>
|
||||
<span *ngSwitchCase="'date'">{{ item[col.prop] | date }}</span>
|
||||
<span *ngSwitchDefault>{{ item[col.prop] }}</span>
|
||||
</span>
|
||||
</td>
|
||||
|
|
|
@ -12,7 +12,7 @@ export class TableComponent<T> implements OnInit {
|
|||
@Input() showHeader = false;
|
||||
@Input() items: T[] = [];
|
||||
@Input() loading = false;
|
||||
@Input() columns: { title: string, prop: string }[] = [];
|
||||
@Input() columns: { title: string, prop: string, type?: string }[] = [];
|
||||
@Input() paginationData: PaginationData = {page: 1, limit: 10};
|
||||
@Input() customActions: { icon: string, label: string, action: (model: T) => void }[] = [];
|
||||
@Input() allowEditing = true;
|
||||
|
@ -30,8 +30,8 @@ export class TableComponent<T> implements OnInit {
|
|||
return this.columns.map(col => col.prop).concat('actions');
|
||||
}
|
||||
|
||||
getType(itemElement: any): typeof itemElement {
|
||||
return typeof itemElement;
|
||||
getType(field: typeof TableComponent.prototype.columns[number] | null, value: any): typeof value | string {
|
||||
return field?.type ?? typeof value;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,13 +19,43 @@
|
|||
{{ editedFulMode?.name || 'Új teljesitési mód' }}
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<app-edit [itemType]="editedFulMode" [createMutation]="modeCreateGQL"
|
||||
<app-edit [itemType]="editedFulMode" creating [createMutation]="modeCreateGQL"
|
||||
[updateMutation]="modeEditGQL" [customItem]="editedFulMode" [fields]="[
|
||||
{name: 'name', title: 'Név'},
|
||||
{name: 'threshold2', title: 'Kettes %'},
|
||||
{name: 'threshold3', title: 'Hármas %'},
|
||||
{name: 'threshold4', title: 'Négyes %'},
|
||||
{name: 'threshold5', title: 'Ötös %'}
|
||||
{name: 'threshold2', title: 'Kettes %', type: 'integer'},
|
||||
{name: 'threshold3', title: 'Hármas %', type: 'integer'},
|
||||
{name: 'threshold4', title: 'Négyes %', type: 'integer'},
|
||||
{name: 'threshold5', title: 'Ötös %', type: 'integer'}
|
||||
]" [beforeSubmit]="beforeFulModeSubmit.bind(this)" [itemSubmitted]="submitFulMode.bind(this)"></app-edit>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<mat-card style="margin-top: 50px" *ngIf="editingFulMode">
|
||||
<mat-card-header>
|
||||
<h3>Követelmények</h3>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<app-list [gql]="requirementListGQL" [queryVariables]="{mode: this.editedFulMode.id}" [columns]="[
|
||||
{prop: 'name', title: 'Név'},
|
||||
{prop: 'description', title: 'Leirás'},
|
||||
{prop: 'minPoints', title: 'Minimum elérendő pontszám'},
|
||||
{prop: 'maxPoints', title: 'Maximálisan elérhető pontszám'},
|
||||
{prop: 'deadline', title: 'Határidő', type: 'date'}
|
||||
]" allowEditing="true" allowNew="true" [editFunction]="editRequirement.bind(this)"
|
||||
[createFunction]="createRequirement.bind(this)"></app-list>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<mat-card *ngIf="editingRequirement">
|
||||
<mat-card-header>
|
||||
{{ editedRequirement?.name || 'Új követelmény' }}
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<app-edit [itemType]="editedRequirement" creating="true" [createMutation]="requirementCreateGQL"
|
||||
[updateMutation]="requirementEditGQL" [customItem]="editedRequirement" [fields]="[
|
||||
{name: 'name', title: 'Név'},
|
||||
{name: 'description', title: 'Leirás'},
|
||||
{name: 'minPoints', title: 'Minimum elérendő pontszám', type: 'integer'},
|
||||
{name: 'maxPoints', title: 'Maximálisan elérhető pontszám', type: 'integer'},
|
||||
{name: 'deadline', title: 'Határidő', type: 'date'}
|
||||
]" [beforeSubmit]="beforeRequirementSubmit.bind(this)" [itemSubmitted]="submitRequirement.bind(this)"></app-edit>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
|
|
@ -6,12 +6,18 @@ import {
|
|||
CourseGQL,
|
||||
CreateCourseGQL,
|
||||
CreateFulfillmentModeGQL,
|
||||
CreateRequirementGQL,
|
||||
EditCourseGQL,
|
||||
EditFulfillmentModeGQL,
|
||||
EditRequirementGQL,
|
||||
FulfillmentMode,
|
||||
FulfillmentModeGQL,
|
||||
FulfillmentModeListGQL,
|
||||
FulfillmentModeUpdateInput,
|
||||
Requirement,
|
||||
RequirementGQL,
|
||||
RequirementListGQL,
|
||||
RequirementUpdateInput,
|
||||
SubjectGQL
|
||||
} from '../../../../services/graphql';
|
||||
|
||||
|
@ -26,12 +32,15 @@ export class CourseEditComponent implements OnInit, CustomTitleComponent {
|
|||
courseId: string;
|
||||
editedFulMode: FulfillmentMode;
|
||||
editingFulMode = false;
|
||||
editedRequirement: Requirement;
|
||||
editingRequirement = false;
|
||||
beforeSubmit = () => ({subjectId: +this.route.snapshot.params.subjectId});
|
||||
|
||||
constructor(private route: ActivatedRoute, public subjectGQL: SubjectGQL,
|
||||
public itemGQL: CourseGQL, public editGQL: EditCourseGQL, public createGQL: CreateCourseGQL,
|
||||
public modeListGQL: FulfillmentModeListGQL, public modeItemGQL: FulfillmentModeGQL, public modeEditGQL: EditFulfillmentModeGQL,
|
||||
public modeCreateGQL: CreateFulfillmentModeGQL) {
|
||||
public modeCreateGQL: CreateFulfillmentModeGQL, public requirementListGQL: RequirementListGQL, public requirementGQL: RequirementGQL,
|
||||
public requirementEditGQL: EditRequirementGQL, public requirementCreateGQL: CreateRequirementGQL) {
|
||||
this.subjectId = route.snapshot.params.subjectId;
|
||||
this.courseId = route.snapshot.params.id;
|
||||
}
|
||||
|
@ -59,7 +68,7 @@ export class CourseEditComponent implements OnInit, CustomTitleComponent {
|
|||
if (val < 0) {
|
||||
val = 0;
|
||||
}
|
||||
((item[prop]) as number) = val > 1 ? val as number / 100 : +val;
|
||||
((item[prop]) as number) = val > 100 ? 100 : +val;
|
||||
}
|
||||
|
||||
thresh('threshold2');
|
||||
|
@ -73,4 +82,23 @@ export class CourseEditComponent implements OnInit, CustomTitleComponent {
|
|||
this.editedFulMode = null;
|
||||
this.editingFulMode = false;
|
||||
}
|
||||
|
||||
async editRequirement(item: Requirement): Promise<void> {
|
||||
this.editingRequirement = true;
|
||||
this.editedRequirement = item;
|
||||
}
|
||||
|
||||
async createRequirement(item: Requirement): Promise<void> {
|
||||
this.editingRequirement = true;
|
||||
this.editedRequirement = null;
|
||||
}
|
||||
|
||||
beforeRequirementSubmit(item: Requirement): Partial<RequirementUpdateInput> {
|
||||
return {...item, fulfillmentModeId: this.editedFulMode.id};
|
||||
}
|
||||
|
||||
submitRequirement(): void {
|
||||
this.editingRequirement = false;
|
||||
this.editedRequirement = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import { Subject, SubjectListGQL } from '../../services/graphql';
|
|||
styleUrls: ['./subject-list.component.css']
|
||||
})
|
||||
export class SubjectListComponent implements OnInit {
|
||||
itemType: Subject;
|
||||
|
||||
constructor(private route: ActivatedRoute, private router: Router, public listGQL: SubjectListGQL) {
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue