Skip to content

Commit

Permalink
Merge pull request #103 from CentreForDigitalHumanities/feature/desig…
Browse files Browse the repository at this point in the history
…nators-component

Feature/designators component
  • Loading branch information
lukavdplas authored Aug 6, 2024
2 parents 98546af + 9e2f3f4 commit 520a0ae
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 0 deletions.
68 changes: 68 additions & 0 deletions frontend/generated/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ export type Query = {
giftDescriptions: Array<GiftDescriptionType>;
letterDescription?: Maybe<LetterDescriptionType>;
letterDescriptions: Array<LetterDescriptionType>;
source: SourceType;
sources: Array<SourceType>;
spaceDescription?: Maybe<SpaceDescriptionType>;
spaceDescriptions: Array<SpaceDescriptionType>;
Expand Down Expand Up @@ -435,6 +436,11 @@ export type QueryLetterDescriptionsArgs = {
};


export type QuerySourceArgs = {
id: Scalars['ID']['input'];
};


export type QuerySpaceDescriptionArgs = {
id: Scalars['ID']['input'];
};
Expand Down Expand Up @@ -517,6 +523,7 @@ export type SourceType = {
editionAuthor: Scalars['String']['output'];
/** The title of the edition used for this source */
editionTitle: Scalars['String']['output'];
episodes: Array<EpisodeType>;
id: Scalars['ID']['output'];
/** The name of the original author of the work, if known */
medievalAuthor: Scalars['String']['output'];
Expand Down Expand Up @@ -697,11 +704,72 @@ export type UpdateOrCreateSourceMutation = {
source?: Maybe<SourceType>;
};

export type DataEntrySourceDetailQueryVariables = Exact<{
id: Scalars['ID']['input'];
}>;


export type DataEntrySourceDetailQuery = { __typename?: 'Query', source: { __typename?: 'SourceType', id: string, name: string, editionAuthor: string, editionTitle: string, medievalAuthor: string, medievalTitle: string, numOfEpisodes: number, episodes: Array<{ __typename?: 'EpisodeType', id: string, name: string, description: string, summary: string, book: string, chapter: string, page: string, agents: Array<{ __typename?: 'AgentDescriptionType', id: string, name: string, isGroup: boolean, describes?: Array<{ __typename?: 'HistoricalPersonType', id: string, identifiable: boolean } | null> | null }>, gifts: Array<{ __typename?: 'GiftDescriptionType', id: string, name: string }>, letters: Array<{ __typename?: 'LetterDescriptionType', id: string, name: string }>, spaces: Array<{ __typename?: 'SpaceDescriptionType', id: string, name: string }> }> } };

export type DataEntrySourceListQueryVariables = Exact<{ [key: string]: never; }>;


export type DataEntrySourceListQuery = { __typename?: 'Query', sources: Array<{ __typename?: 'SourceType', id: string, name: string, editionAuthor: string, editionTitle: string, medievalAuthor: string, medievalTitle: string, numOfEpisodes: number }> };

export const DataEntrySourceDetailDocument = gql`
query DataEntrySourceDetail($id: ID!) {
source(id: $id) {
id
name
editionAuthor
editionTitle
medievalAuthor
medievalTitle
numOfEpisodes
episodes {
id
name
description
summary
book
chapter
page
agents {
id
name
isGroup
describes {
id
identifiable
}
}
gifts {
id
name
}
letters {
id
name
}
spaces {
id
name
}
}
}
}
`;

@Injectable({
providedIn: 'root'
})
export class DataEntrySourceDetailGQL extends Apollo.Query<DataEntrySourceDetailQuery, DataEntrySourceDetailQueryVariables> {
override document = DataEntrySourceDetailDocument;

constructor(apollo: Apollo.Apollo) {
super(apollo);
}
}
export const DataEntrySourceListDocument = gql`
query DataEntrySourceList {
sources {
Expand Down
2 changes: 2 additions & 0 deletions frontend/generated/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ type Query {
giftDescriptions(episodeId: ID, sourceId: ID): [GiftDescriptionType!]!
letterDescription(id: ID!): LetterDescriptionType
letterDescriptions(episodeId: ID, sourceId: ID): [LetterDescriptionType!]!
source(id: ID!): SourceType!
sources: [SourceType!]!
spaceDescription(id: ID!): SpaceDescriptionType
spaceDescriptions(sourceId: ID): [SpaceDescriptionType!]!
Expand Down Expand Up @@ -539,6 +540,7 @@ type SourceType {

"""The title of the edition used for this source"""
editionTitle: String!
episodes: [EpisodeType!]!
id: ID!

"""The name of the original author of the work, if known"""
Expand Down
18 changes: 18 additions & 0 deletions frontend/src/app/data-entry/shared/data-entry-shared.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NgModule } from '@angular/core';
import { SharedModule } from '@shared/shared.module';
import { DesignatorsControlComponent } from './designators-control/designators-control.component';



@NgModule({
declarations: [
DesignatorsControlComponent
],
imports: [
SharedModule
],
exports: [
DesignatorsControlComponent,
]
})
export class DataEntrySharedModule { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<div class="mb-3">
<p>Designators</p>
<p *ngIf="designators$.value.length === 0">
<i>No designators added.</i>
</p>
<ul class="list-group">
<li *ngFor="let designator of designators$.value; let i = index"
class="list-group-item hstack gap-3">
<span>{{designator}}</span>
<button class="btn ms-auto" type="button"
[disabled]="disabled"
(blur)="blur$.next()"
(click)="removeDesignator(i)">
<lc-icon [icon]="actionIcons.remove"
[attr.aria-label]="designatorRemoveLabel(designator)" />
</button>
</li>
</ul>
</div>

<form class="mb-3" [formGroup]="addForm" (ngSubmit)="onAddFormSubmit()">
<label class="form-label" for="input-new-designator">Add a designator</label>
<div class="input-group mb-3">
<input type="text" class="form-control" id="input-new-designator"
[formControl]="addForm.controls.designator"
(blur)="blur$.next()">
<button class="btn btn-primary" type="submit"
[disabled]="disabled"
(blur)="blur$.next()">
<lc-icon [icon]="actionIcons.add" aria-label="add designator" />
</button>
</div>
</form>
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { DesignatorsControlComponent } from './designators-control.component';
import { SharedTestingModule } from '@shared/shared-testing.module';

describe('DesignatorsControlComponent', () => {
let component: DesignatorsControlComponent;
let fixture: ComponentFixture<DesignatorsControlComponent>;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [DesignatorsControlComponent],
imports: [SharedTestingModule],
});
fixture = TestBed.createComponent(DesignatorsControlComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { Component, forwardRef, Input, OnDestroy } from '@angular/core';
import { ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { actionIcons } from '@shared/icons';
import { BehaviorSubject, Subject, Subscription } from 'rxjs';
import _ from 'underscore';

@Component({
selector: 'lc-designators-control',
templateUrl: './designators-control.component.html',
styleUrls: ['./designators-control.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DesignatorsControlComponent),
multi: true,
}
],
})
export class DesignatorsControlComponent implements ControlValueAccessor, OnDestroy {
@Input({ required: true }) formControl!: FormControl<string[]>;

designators$ = new BehaviorSubject<string[]>([]);
blur$ = new Subject<void>();
disabled = false;

addForm = new FormGroup({
designator: new FormControl<string>('', {
nonNullable: true,
validators: [
Validators.required,
Validators.minLength(1),
]
})
});

actionIcons = actionIcons;

private onChangeSubscription?: Subscription;
private onTouchedSubscription?: Subscription;

writeValue(obj: string[]): void {
this.designators$.next(obj);
}

registerOnChange(fn: (_: unknown) => void): void {
this.onChangeSubscription?.unsubscribe();
this.onChangeSubscription = this.designators$.subscribe(fn);
}

registerOnTouched(fn: (_: unknown) => void): void {
this.onTouchedSubscription?.unsubscribe();
this.onTouchedSubscription = this.blur$.subscribe(fn);
}

ngOnDestroy(): void {
this.designators$.complete();
this.blur$.complete();
}

setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (isDisabled) {
this.addForm.disable();
} else {
this.addForm.enable();
}
}

onAddFormSubmit() {
if (this.addForm.valid) {
const designator = this.addForm.controls.designator.value;
this.designators$.next(this.designators$.value.concat([designator]));
this.addForm.reset({ designator: '' });
}
}

removeDesignator(index: number) {
const spliced = _.clone(this.designators$.value)
spliced.splice(index, 1);
this.designators$.next(spliced);
}

designatorRemoveLabel(designator: string): string {
return `remove designator "${designator}"`;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";

import { EpisodePreviewComponent } from "./episode-preview.component";
import { SharedTestingModule } from "@shared/shared-testing.module";

describe("EpisodePreviewComponent", () => {
let component: EpisodePreviewComponent;
Expand All @@ -9,9 +10,23 @@ describe("EpisodePreviewComponent", () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [EpisodePreviewComponent],
imports: [SharedTestingModule],
});
fixture = TestBed.createComponent(EpisodePreviewComponent);
component = fixture.componentInstance;
component.episode = {
id: '1',
name: 'Test',
description: 'Test episode',
summary: '',
book: '',
chapter: '',
page: '',
agents: [],
gifts: [],
letters: [],
spaces: [],
}
fixture.detectChanges();
});

Expand Down

0 comments on commit 520a0ae

Please sign in to comment.