Merge branch 'master' of github.com:fLotte-meets-HWR-DB/frontend

pull/3/head
leonnicolas 4 years ago
commit 0bfd28877d

@ -1,4 +1,4 @@
<div #booleanInputType *ngIf="inputType == 'boolean'"> <div #booleanInputType *ngIf="inputType == 'Boolean'">
<mat-checkbox <mat-checkbox
class="checkbox" class="checkbox"
[disabled]="!editable" [disabled]="!editable"
@ -7,7 +7,7 @@
></mat-checkbox> ></mat-checkbox>
</div> </div>
<div #enumInputType *ngIf="inputType == 'enum'"> <div #enumInputType *ngIf="inputType.startsWith('Enum//')">
<mat-form-field *ngIf="editable; else nonEditableText"> <mat-form-field *ngIf="editable; else nonEditableText">
<mat-select [(ngModel)]="value" (ngModelChange)="change($event)"> <mat-select [(ngModel)]="value" (ngModelChange)="change($event)">
<mat-option *ngFor="let option of enumValues" [value]="option"> <mat-option *ngFor="let option of enumValues" [value]="option">
@ -20,7 +20,7 @@
</ng-template> </ng-template>
</div> </div>
<div #otherInputType *ngIf="inputType != 'enum' && inputType != 'boolean'"> <div #otherInputType *ngIf="inputType === 'number' || inputType === 'text'">
<mat-form-field *ngIf="editable; else nonEditableText"> <mat-form-field *ngIf="editable; else nonEditableText">
<input <input
matInput matInput

@ -1,5 +1,4 @@
import { Component, Input, Output, EventEmitter } from '@angular/core'; import { Component, Input, Output, EventEmitter } from '@angular/core';
import { catchError } from 'rxjs/operators';
@Component({ @Component({
selector: 'app-cell', selector: 'app-cell',
@ -14,8 +13,22 @@ export class CellComponent {
editable = false; editable = false;
@Input() @Input()
inputType = 'text'; inputType = 'text';
@Input()
enumValues: string[] = []; enumValues = [];
ngOnChanges() {
if (this.inputType.split('//')[0] === 'Enum') {
this.enumValues = this.inputType.split('//').slice(1);
} else if (this.inputType === 'Int' || this.inputType === 'Float') {
this.inputType = 'number';
} else if (this.inputType === 'ID' || this.inputType === 'String') {
this.inputType = 'text';
} else if (this.inputType === 'Boolean') {
} else {
console.log(this.inputType);
}
}
change(newValue) { change(newValue) {
this.value = this.inputType === 'number' ? +newValue : newValue; this.value = this.inputType === 'number' ? +newValue : newValue;

@ -1,5 +1,5 @@
query GetCargoBikes { query GetCargoBikes {
...Introspection ...SchemaIntrospection
cargoBikes(limit: 100, offset: 0) { cargoBikes(limit: 100, offset: 0) {
...CargoBikeFields ...CargoBikeFields

@ -1,4 +1,4 @@
fragment Introspection on Query { fragment GroupIntrospection on Query {
__type(name: "Group") { __type(name: "Group") {
name name
enumValues { enumValues {
@ -6,3 +6,26 @@ fragment Introspection on Query {
} }
} }
} }
fragment SchemaIntrospection on Query {
__schema {
types {
name
kind
enumValues {
name
}
fields {
name
type {
name
kind
ofType {
name
kind
}
}
}
}
}
}

@ -19,7 +19,7 @@ function isPartOfSelectionSet(
if (variablePath.length === 1) { if (variablePath.length === 1) {
return true; return true;
} }
return isPartOfSelectionSet(variablePath.slice(1).join(), nextSelectionObject); return isPartOfSelectionSet(variablePath.slice(1).join('.'), nextSelectionObject);
} else { } else {
return false; return false;
} }

@ -62,7 +62,6 @@
[editable]="element.isLockedByMe && !isReadonly(column)" [editable]="element.isLockedByMe && !isReadonly(column)"
[(value)]="element[column]" [(value)]="element[column]"
[inputType]="getType(column, element)" [inputType]="getType(column, element)"
[enumValues]="getEnumValues(column)"
></app-cell> ></app-cell>
</td> </td>
</ng-container> </ng-container>

@ -10,6 +10,7 @@ import {
CargoBikeFieldsMutableFragmentDoc, CargoBikeFieldsMutableFragmentDoc,
CargoBikeUpdateInput, CargoBikeUpdateInput,
} from 'src/generated/graphql'; } from 'src/generated/graphql';
import { SchemaService } from 'src/app/services/schema.service';
@Component({ @Component({
selector: 'app-bikes', selector: 'app-bikes',
@ -18,9 +19,9 @@ import {
}) })
export class BikesComponent { export class BikesComponent {
columnInfo = [ columnInfo = [
{ name: 'name', header: 'Name', type: 'string', sticky: true }, { name: 'name', header: 'Name', sticky: true },
{ name: 'id', header: 'ID', type: 'number', readonly: true }, { name: 'id', header: 'ID', readonly: true },
{ name: 'group', header: 'Gruppe', type: 'enum', enumValues: [] }, { name: 'group', header: 'Gruppe'},
]; ];
//properties that wont be shown in the table //properties that wont be shown in the table
@ -47,16 +48,13 @@ export class BikesComponent {
relockingInterval = null; relockingInterval = null;
relockingDuration = 1000 * 60 * 1; relockingDuration = 1000 * 60 * 1;
constructor(private bikesService: BikesService) { constructor(
private bikesService: BikesService,
private schemaService: SchemaService
) {
this.displayedColumns.unshift(this.additionalColumnsFront[0]); this.displayedColumns.unshift(this.additionalColumnsFront[0]);
this.displayedColumns.push(this.additionalColumnsBack[0]); this.displayedColumns.push(this.additionalColumnsBack[0]);
bikesService.groupEnum.subscribe((groupEnum) => {
this.columnInfo.find(
(column) => column.name === 'group'
).enumValues = groupEnum;
});
bikesService.loadingRowIds.subscribe((rowIds) => { bikesService.loadingRowIds.subscribe((rowIds) => {
this.loadingRowIds = rowIds; this.loadingRowIds = rowIds;
}); });
@ -75,7 +73,7 @@ export class BikesComponent {
} }
for (const prop in this.data[0]) { for (const prop in this.data[0]) {
if (!this.blacklistedColumns.includes(prop) && !prop.includes("__")) { if (!this.blacklistedColumns.includes(prop) && !prop.includes('__')) {
this.dataColumns.push(prop); this.dataColumns.push(prop);
} }
} }
@ -122,17 +120,17 @@ export class BikesComponent {
} }
getType(propertyName: string, row) { getType(propertyName: string, row) {
//TODO: get type from introspection query //console.log(propertyName, this.schemaService.getPropertyTypeFromSchema("CargoBike", propertyName))
return ( return (
this.columnInfo.find((column) => column.name === propertyName)?.type || this.schemaService.getPropertyTypeFromSchema("CargoBike", propertyName)
(typeof row[propertyName])
); );
} }
isReadonly(propertyName: string) { isReadonly(propertyName: string) {
return ( return (
this.columnInfo.find((column) => column.name === propertyName) this.columnInfo.find((column) => column.name === propertyName)
?.readonly || !isPartOfGraphQLDoc(propertyName, CargoBikeFieldsMutableFragmentDoc) ?.readonly ||
!isPartOfGraphQLDoc(propertyName, CargoBikeFieldsMutableFragmentDoc)
); );
} }
@ -143,13 +141,6 @@ export class BikesComponent {
); );
} }
getEnumValues(propertyName: string) {
return (
this.columnInfo.find((column) => column.name === propertyName)
?.enumValues || []
);
}
isLoading(id: string) { isLoading(id: string) {
return this.loadingRowIds.includes(id); return this.loadingRowIds.includes(id);
} }

@ -1,5 +1,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
import { SchemaService } from './schema.service';
import { import {
GetCargoBikesGQL, GetCargoBikesGQL,
GetCargoBikesQuery, GetCargoBikesQuery,
@ -28,6 +29,7 @@ export class BikesService {
groupEnum: BehaviorSubject<string[]> = new BehaviorSubject<string[]>([]); groupEnum: BehaviorSubject<string[]> = new BehaviorSubject<string[]>([]);
constructor( constructor(
private schemaService: SchemaService,
private getCargoBikesGQL: GetCargoBikesGQL, private getCargoBikesGQL: GetCargoBikesGQL,
private getCargoBikeByIdGQL: GetCargoBikeByIdGQL, private getCargoBikeByIdGQL: GetCargoBikeByIdGQL,
private updateCargoBikeGQL: UpdateCargoBikeGQL, private updateCargoBikeGQL: UpdateCargoBikeGQL,
@ -50,8 +52,7 @@ export class BikesService {
loadBikes() { loadBikes() {
this.getCargoBikesGQL.fetch().subscribe((result) => { this.getCargoBikesGQL.fetch().subscribe((result) => {
this.bikes.next(result.data.cargoBikes); this.bikes.next(result.data.cargoBikes);
let enumValues = result.data.__type.enumValues.map((value) => value.name); this.schemaService.nextSchema(result.data.__schema);
this.groupEnum.next(enumValues);
}); });
} }

@ -0,0 +1,45 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { find } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class SchemaService {
schema: BehaviorSubject<any> = new BehaviorSubject({});
nextSchema(schema: any) {
this.schema.next(schema);
}
/** expects startingObject and variablePath and returns its type e.g. cargoBike, security.name -> returns the type of the name variable */
getPropertyTypeFromSchema(
startingObjectName: String,
variable: String
): String {
const variablePath = variable.split('.');
const types = this.schema.value.types;
const startingObject = types.find(
(type) => type.name === startingObjectName
);
const field = startingObject.fields.find(
(field) => field.name === variablePath[0]
);
const type = field.type.name || field.type.ofType.name;
if (variablePath.length === 1) {
if ((field.type.kind === "ENUM")) {
return "Enum//" + this.getEnumValuesFromSchema(field.type.name).join("//");
}
return type;
} else {
return this.getPropertyTypeFromSchema(type, variablePath.slice(1).join('.'));
}
}
getEnumValuesFromSchema(typeName: String): String[] {
const types= this.schema.value.types;
const type = types.find(type => type.name === typeName);
return type.enumValues.map((value) => value.name);
}
}

@ -1668,6 +1668,22 @@ export enum CacheControlScope {
} }
/** A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations. */
export type __Schema = {
__typename?: '__Schema';
description?: Maybe<Scalars['String']>;
/** A list of all types supported by this server. */
types: Array<__Type>;
/** The type that query operations will be rooted at. */
queryType: __Type;
/** If this server supports mutation, the type that mutation operations will be rooted at. */
mutationType?: Maybe<__Type>;
/** If this server support subscription, the type that subscription operations will be rooted at. */
subscriptionType?: Maybe<__Type>;
/** A list of all directives supported by this server. */
directives: Array<__Directive>;
};
/** /**
* The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum. * The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.
* *
@ -1757,6 +1773,62 @@ export type __EnumValue = {
deprecationReason?: Maybe<Scalars['String']>; deprecationReason?: Maybe<Scalars['String']>;
}; };
/**
* A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.
*
* In some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.
*/
export type __Directive = {
__typename?: '__Directive';
name: Scalars['String'];
description?: Maybe<Scalars['String']>;
isRepeatable: Scalars['Boolean'];
locations: Array<__DirectiveLocation>;
args: Array<__InputValue>;
};
/** A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies. */
export enum __DirectiveLocation {
/** Location adjacent to a query operation. */
Query = 'QUERY',
/** Location adjacent to a mutation operation. */
Mutation = 'MUTATION',
/** Location adjacent to a subscription operation. */
Subscription = 'SUBSCRIPTION',
/** Location adjacent to a field. */
Field = 'FIELD',
/** Location adjacent to a fragment definition. */
FragmentDefinition = 'FRAGMENT_DEFINITION',
/** Location adjacent to a fragment spread. */
FragmentSpread = 'FRAGMENT_SPREAD',
/** Location adjacent to an inline fragment. */
InlineFragment = 'INLINE_FRAGMENT',
/** Location adjacent to a variable definition. */
VariableDefinition = 'VARIABLE_DEFINITION',
/** Location adjacent to a schema definition. */
Schema = 'SCHEMA',
/** Location adjacent to a scalar definition. */
Scalar = 'SCALAR',
/** Location adjacent to an object type definition. */
Object = 'OBJECT',
/** Location adjacent to a field definition. */
FieldDefinition = 'FIELD_DEFINITION',
/** Location adjacent to an argument definition. */
ArgumentDefinition = 'ARGUMENT_DEFINITION',
/** Location adjacent to an interface definition. */
Interface = 'INTERFACE',
/** Location adjacent to a union definition. */
Union = 'UNION',
/** Location adjacent to an enum definition. */
Enum = 'ENUM',
/** Location adjacent to an enum value definition. */
EnumValue = 'ENUM_VALUE',
/** Location adjacent to an input object type definition. */
InputObject = 'INPUT_OBJECT',
/** Location adjacent to an input object field definition. */
InputFieldDefinition = 'INPUT_FIELD_DEFINITION'
}
export type GetCargoBikeByIdQueryVariables = Exact<{ export type GetCargoBikeByIdQueryVariables = Exact<{
id: Scalars['ID']; id: Scalars['ID'];
}>; }>;
@ -1818,7 +1890,7 @@ export type GetCargoBikesQuery = (
{ __typename?: 'CargoBike' } { __typename?: 'CargoBike' }
& CargoBikeFieldsFragment & CargoBikeFieldsFragment
)>> } )>> }
& IntrospectionFragment & SchemaIntrospectionFragment
); );
export type BikeEventFieldsFragment = ( export type BikeEventFieldsFragment = (
@ -1867,7 +1939,7 @@ export type CargoBikeFieldsFragment = (
& CargoBikeFieldsMutableFragment & CargoBikeFieldsMutableFragment
); );
export type IntrospectionFragment = ( export type GroupIntrospectionFragment = (
{ __typename?: 'Query' } { __typename?: 'Query' }
& { __type?: Maybe<( & { __type?: Maybe<(
{ __typename?: '__Type' } { __typename?: '__Type' }
@ -1879,6 +1951,32 @@ export type IntrospectionFragment = (
)> } )> }
); );
export type SchemaIntrospectionFragment = (
{ __typename?: 'Query' }
& { __schema: (
{ __typename?: '__Schema' }
& { types: Array<(
{ __typename?: '__Type' }
& Pick<__Type, 'name' | 'kind'>
& { enumValues?: Maybe<Array<(
{ __typename?: '__EnumValue' }
& Pick<__EnumValue, 'name'>
)>>, fields?: Maybe<Array<(
{ __typename?: '__Field' }
& Pick<__Field, 'name'>
& { type: (
{ __typename?: '__Type' }
& Pick<__Type, 'name' | 'kind'>
& { ofType?: Maybe<(
{ __typename?: '__Type' }
& Pick<__Type, 'name' | 'kind'>
)> }
) }
)>> }
)> }
) }
);
export type LendingStationFieldsGeneralFragment = ( export type LendingStationFieldsGeneralFragment = (
{ __typename?: 'LendingStation' } { __typename?: 'LendingStation' }
& Pick<LendingStation, 'id' | 'name'> & Pick<LendingStation, 'id' | 'name'>
@ -2050,8 +2148,8 @@ export const CargoBikeFieldsFragmentDoc = gql`
${CargoBikeFieldsMutableFragmentDoc} ${CargoBikeFieldsMutableFragmentDoc}
${ProviderFieldsGeneralFragmentDoc} ${ProviderFieldsGeneralFragmentDoc}
${LendingStationFieldsGeneralFragmentDoc}`; ${LendingStationFieldsGeneralFragmentDoc}`;
export const IntrospectionFragmentDoc = gql` export const GroupIntrospectionFragmentDoc = gql`
fragment Introspection on Query { fragment GroupIntrospection on Query {
__type(name: "Group") { __type(name: "Group") {
name name
enumValues { enumValues {
@ -2060,6 +2158,30 @@ export const IntrospectionFragmentDoc = gql`
} }
} }
`; `;
export const SchemaIntrospectionFragmentDoc = gql`
fragment SchemaIntrospection on Query {
__schema {
types {
name
kind
enumValues {
name
}
fields {
name
type {
name
kind
ofType {
name
kind
}
}
}
}
}
}
`;
export const GetCargoBikeByIdDocument = gql` export const GetCargoBikeByIdDocument = gql`
query GetCargoBikeById($id: ID!) { query GetCargoBikeById($id: ID!) {
cargoBikeById(id: $id) { cargoBikeById(id: $id) {
@ -2134,12 +2256,12 @@ export const UnlockCargoBikeDocument = gql`
} }
export const GetCargoBikesDocument = gql` export const GetCargoBikesDocument = gql`
query GetCargoBikes { query GetCargoBikes {
...Introspection ...SchemaIntrospection
cargoBikes(limit: 100, offset: 0) { cargoBikes(limit: 100, offset: 0) {
...CargoBikeFields ...CargoBikeFields
} }
} }
${IntrospectionFragmentDoc} ${SchemaIntrospectionFragmentDoc}
${CargoBikeFieldsFragmentDoc}`; ${CargoBikeFieldsFragmentDoc}`;
@Injectable({ @Injectable({

Loading…
Cancel
Save